From 04cfca0ede0a939ad4158b127573a38b2cc47d50 Mon Sep 17 00:00:00 2001 From: Regalis Date: Sat, 12 Dec 2015 16:23:01 +0200 Subject: [PATCH] Multiplayer fixes --- .../Source/Characters/AI/EnemyAIController.cs | 2 ++ Subsurface/Source/Characters/AICharacter.cs | 21 +++++++++--------- Subsurface/Source/Characters/Character.cs | 12 +++++----- Subsurface/Source/Characters/CharacterHUD.cs | 2 +- .../Source/Items/Components/ItemLabel.cs | 2 +- .../Items/Components/Machines/Controller.cs | 6 ++--- .../Source/Items/Components/Machines/Radar.cs | 5 ++++- Subsurface/Source/Items/Components/Turret.cs | 4 ++-- Subsurface/Source/Map/Submarine.cs | 8 +++++++ Subsurface/Source/Map/SubmarineBody.cs | 2 +- Subsurface/Source/Networking/GameClient.cs | 9 ++++---- Subsurface/Source/Networking/GameServer.cs | 4 ++-- Subsurface/Source/Utils/Rand.cs | 6 ++--- Subsurface_Solution.v12.suo | Bin 788480 -> 788480 bytes 14 files changed, 46 insertions(+), 37 deletions(-) diff --git a/Subsurface/Source/Characters/AI/EnemyAIController.cs b/Subsurface/Source/Characters/AI/EnemyAIController.cs index 85016b0c9..2460f3c0f 100644 --- a/Subsurface/Source/Characters/AI/EnemyAIController.cs +++ b/Subsurface/Source/Characters/AI/EnemyAIController.cs @@ -64,6 +64,8 @@ namespace Barotrauma public EnemyAIController(Character c, string file) : base(c) { + if (GameMain.Client != null && GameMain.Server == null) c.Enabled = false; + targetMemories = new Dictionary(); XDocument doc = ToolBox.TryLoadXml(file); diff --git a/Subsurface/Source/Characters/AICharacter.cs b/Subsurface/Source/Characters/AICharacter.cs index e1247ffdb..81522eaab 100644 --- a/Subsurface/Source/Characters/AICharacter.cs +++ b/Subsurface/Source/Characters/AICharacter.cs @@ -42,7 +42,6 @@ namespace Barotrauma public AICharacter(string file, Vector2 position, CharacterInfo characterInfo = null, bool isNetworkPlayer = false) : base(file, position, characterInfo, isNetworkPlayer) { - if (GameMain.Client != null && GameMain.Server == null) Enabled = false; } public void SetAI(AIController aiController) @@ -98,10 +97,10 @@ namespace Barotrauma //{ //if (RefLimb.ignoreCollisions) continue; - if (AnimController.RefLimb.SimPosition.Length() > NetConfig.CharacterIgnoreDistance) return false; + if ((AnimController.RefLimb.SimPosition - Submarine.Loaded.SimPosition).Length() > NetConfig.CharacterIgnoreDistance) return false; - message.WriteRangedSingle(AnimController.RefLimb.SimPosition.X, -NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); - message.WriteRangedSingle(AnimController.RefLimb.SimPosition.Y, -NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); + message.Write(AnimController.RefLimb.SimPosition.X); + message.Write(AnimController.RefLimb.SimPosition.Y); message.Write(AnimController.RefLimb.Rotation); @@ -114,14 +113,14 @@ namespace Barotrauma aiController.FillNetworkData(message); return true; case NetworkEventType.EntityUpdate: - if (AnimController.RefLimb.SimPosition.Length() > NetConfig.CharacterIgnoreDistance) return false; + if ((AnimController.RefLimb.SimPosition - Submarine.Loaded.SimPosition).Length() > NetConfig.CharacterIgnoreDistance) return false; message.Write(AnimController.TargetDir == Direction.Right); message.WriteRangedSingle(MathHelper.Clamp(AnimController.TargetMovement.X, -1.0f, 1.0f), -1.0f, 1.0f, 8); message.WriteRangedSingle(MathHelper.Clamp(AnimController.TargetMovement.X, -1.0f, 1.0f), -1.0f, 1.0f, 8); - message.WriteRangedSingle(AnimController.RefLimb.SimPosition.X, -NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); - message.WriteRangedSingle(AnimController.RefLimb.SimPosition.Y, -NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); + message.Write(AnimController.RefLimb.SimPosition.X); + message.Write(AnimController.RefLimb.SimPosition.Y); return true; } @@ -149,8 +148,8 @@ namespace Barotrauma try { - limbPos.X = message.ReadRangedSingle(-NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); - limbPos.Y = message.ReadRangedSingle(-NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); + limbPos.X = message.ReadFloat(); + limbPos.Y = message.ReadFloat(); rotation = message.ReadFloat(); } @@ -196,8 +195,8 @@ namespace Barotrauma targetMovement.X = message.ReadRangedSingle(-1.0f, 1.0f, 8); targetMovement.Y = message.ReadRangedSingle(-1.0f, 1.0f, 8); - pos.X = message.ReadRangedSingle(-NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); - pos.Y = message.ReadRangedSingle(-NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); + pos.X = message.ReadFloat(); + pos.Y = message.ReadFloat(); //vel.X = message.ReadFloat(); //vel.Y = message.ReadFloat(); diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index f91e1a1df..82497a89a 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -988,7 +988,7 @@ namespace Barotrauma { if (!Enabled) return; - Vector2 pos = ConvertUnits.ToDisplayUnits(AnimController.Limbs[0].SimPosition); + Vector2 pos = AnimController.Limbs[0].WorldPosition; pos.Y = -pos.Y; if (this == controlled) return; @@ -1335,10 +1335,10 @@ namespace Barotrauma message.Write(AnimController.Dir > 0.0f); } - if (AnimController.RefLimb.SimPosition.Length() > NetConfig.CharacterIgnoreDistance) return true; + if ((AnimController.RefLimb.SimPosition - Submarine.Loaded.SimPosition).Length() > NetConfig.CharacterIgnoreDistance) return true; - message.WriteRangedSingle(AnimController.RefLimb.SimPosition.X, -NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); - message.WriteRangedSingle(AnimController.RefLimb.SimPosition.Y, -NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); + message.Write(AnimController.RefLimb.SimPosition.X); + message.Write(AnimController.RefLimb.SimPosition.Y); return true; default: @@ -1505,8 +1505,8 @@ namespace Barotrauma } try { - pos.X = message.ReadRangedSingle(-NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); - pos.Y = message.ReadRangedSingle(-NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); + pos.X = message.ReadFloat(); + pos.Y = message.ReadFloat(); } catch diff --git a/Subsurface/Source/Characters/CharacterHUD.cs b/Subsurface/Source/Characters/CharacterHUD.cs index 63dfb0a46..ed61c57fd 100644 --- a/Subsurface/Source/Characters/CharacterHUD.cs +++ b/Subsurface/Source/Characters/CharacterHUD.cs @@ -54,7 +54,7 @@ namespace Barotrauma if (character.ClosestCharacter != null && (character.ClosestCharacter.IsDead || character.ClosestCharacter.Stun > 0.0f)) { - Vector2 startPos = character.Position + (character.ClosestCharacter.Position - character.Position) * 0.7f; + Vector2 startPos = character.Position + (character.ClosestCharacter.WorldPosition - character.WorldPosition) * 0.7f; startPos = cam.WorldToScreen(startPos); Vector2 textPos = startPos; diff --git a/Subsurface/Source/Items/Components/ItemLabel.cs b/Subsurface/Source/Items/Components/ItemLabel.cs index 814db280a..133b5e3ec 100644 --- a/Subsurface/Source/Items/Components/ItemLabel.cs +++ b/Subsurface/Source/Items/Components/ItemLabel.cs @@ -61,7 +61,7 @@ namespace Barotrauma.Items.Components { base.Draw(spriteBatch, editing); - textBlock.Rect = new Rectangle(item.WorldRect.X, -(item.WorldRect.Y - item.Rect.Height/2), item.Rect.Width, item.Rect.Height); + textBlock.Rect = new Rectangle((int)item.DrawPosition.X - item.Rect.Width/2, -(int)(item.DrawPosition.Y + item.Rect.Height/2), item.Rect.Width, item.Rect.Height); textBlock.Draw(spriteBatch); } } diff --git a/Subsurface/Source/Items/Components/Machines/Controller.cs b/Subsurface/Source/Items/Components/Machines/Controller.cs index ea2d91c34..5775cac99 100644 --- a/Subsurface/Source/Items/Components/Machines/Controller.cs +++ b/Subsurface/Source/Items/Components/Machines/Controller.cs @@ -118,7 +118,7 @@ namespace Barotrauma.Items.Components fmj.WorldAnchorB = position; } - item.SendSignal(ToolBox.Vector2ToString(character.CursorPosition), "position_out"); + item.SendSignal(ToolBox.Vector2ToString(character.CursorWorldPosition), "position_out"); } public override bool Use(float deltaTime, Character activator = null) @@ -152,12 +152,12 @@ namespace Barotrauma.Items.Components { if (c2 == null || c2.Item==null || !c2.Item.Prefab.FocusOnSelected) continue; - Vector2 centerPos = c2.Item.Position; + Vector2 centerPos = c2.Item.WorldPosition; if (character == Character.Controlled && cam != null) { Lights.LightManager.ViewPos = centerPos; - cam.TargetPos = c2.Item.Position; + cam.TargetPos = c2.Item.WorldPosition; } break; diff --git a/Subsurface/Source/Items/Components/Machines/Radar.cs b/Subsurface/Source/Items/Components/Machines/Radar.cs index 6018172d8..d7c805cd4 100644 --- a/Subsurface/Source/Items/Components/Machines/Radar.cs +++ b/Subsurface/Source/Items/Components/Machines/Radar.cs @@ -50,6 +50,8 @@ namespace Barotrauma.Items.Components public override void Update(float deltaTime, Camera cam) { + currPowerConsumption = powerConsumption; + base.Update(deltaTime, cam); for (int i = radarBlips.Count - 1; i >= 0; i-- ) @@ -71,6 +73,8 @@ namespace Barotrauma.Items.Components { pingState = 0.0f; } + + voltage = 0.0f; } public override bool Use(float deltaTime, Character character = null) @@ -262,7 +266,6 @@ namespace Barotrauma.Items.Components prevPos = pos; } - voltage = 0.0f; } private void DrawBlip(SpriteBatch spriteBatch, RadarBlip blip, Vector2 center, Color color, float radius) diff --git a/Subsurface/Source/Items/Components/Turret.cs b/Subsurface/Source/Items/Components/Turret.cs index 83b798eff..225c389f3 100644 --- a/Subsurface/Source/Items/Components/Turret.cs +++ b/Subsurface/Source/Items/Components/Turret.cs @@ -153,7 +153,7 @@ namespace Barotrauma.Items.Components projectile.body.ResetDynamics(); projectile.body.Enabled = true; - projectile.SetTransform(ConvertUnits.ToSimUnits(new Vector2(item.Rect.X + barrelPos.X, item.Rect.Y - barrelPos.Y)), -rotation); + projectile.SetTransform(ConvertUnits.ToSimUnits(new Vector2(item.WorldRect.X + barrelPos.X, item.WorldRect.Y - barrelPos.Y)), -rotation); projectiles[0].Use(deltaTime); if (projectile.container != null) projectile.container.RemoveContained(projectile); @@ -301,7 +301,7 @@ namespace Barotrauma.Items.Components case "position_in": Vector2 receivedPos = ToolBox.ParseToVector2(signal, false); - Vector2 centerPos = new Vector2(item.Rect.X + barrelPos.X, item.Rect.Y - barrelPos.Y); + Vector2 centerPos = new Vector2(item.WorldRect.X + barrelPos.X, item.WorldRect.Y - barrelPos.Y); Vector2 offset = receivedPos - centerPos; offset.Y = -offset.Y; diff --git a/Subsurface/Source/Map/Submarine.cs b/Subsurface/Source/Map/Submarine.cs index 0d265c30e..e7371907f 100644 --- a/Subsurface/Source/Map/Submarine.cs +++ b/Subsurface/Source/Map/Submarine.cs @@ -110,6 +110,14 @@ namespace Barotrauma private set; } + public override Vector2 SimPosition + { + get + { + return ConvertUnits.ToSimUnits(Position); + } + } + public Vector2 Velocity { get { return subBody==null ? Vector2.Zero : subBody.Velocity; } diff --git a/Subsurface/Source/Map/SubmarineBody.cs b/Subsurface/Source/Map/SubmarineBody.cs index 57dc36047..79aa09b8c 100644 --- a/Subsurface/Source/Map/SubmarineBody.cs +++ b/Subsurface/Source/Map/SubmarineBody.cs @@ -402,7 +402,7 @@ namespace Barotrauma } var ragdoll = limb.character.AnimController; - ragdoll.FindHull(); + ragdoll.FindHull(); return false; diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index 0194b5b11..dfd784553 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -3,6 +3,7 @@ using Lidgren.Network; using Microsoft.Xna.Framework; using System.Collections.Generic; using Barotrauma.Networking.ReliableMessages; +using FarseerPhysics; namespace Barotrauma.Networking { @@ -356,7 +357,7 @@ namespace Barotrauma.Networking if (myCharacter.IsDead) { Character.Controlled = null; - GameMain.GameScreen.Cam.TargetPos = Vector2.Zero; + //GameMain.GameScreen.Cam.TargetPos = Vector2.Zero; } else if (gameStarted) { @@ -742,7 +743,7 @@ namespace Barotrauma.Networking float closestDist = 0.0f; foreach (WayPoint wp in WayPoint.WayPointList) { - float dist = Vector2.Distance(wp.SimPosition, position); + float dist = Vector2.Distance(wp.WorldPosition, position); if (closestWaypoint != null && dist > closestDist) continue; closestWaypoint = wp; @@ -750,9 +751,7 @@ namespace Barotrauma.Networking continue; } - Character character = (closestWaypoint == null) ? - Character.Create(ch, position, !isMyCharacter) : - Character.Create(ch, closestWaypoint, !isMyCharacter); + Character character = Character.Create(ch, position, !isMyCharacter); character.ID = ID; diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 9f130bf95..ee373c18c 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -1223,8 +1223,8 @@ namespace Barotrauma.Networking message.Write((byte)character.Info.HeadSpriteId); - message.Write(character.SimPosition.X); - message.Write(character.SimPosition.Y); + message.Write(character.WorldPosition.X); + message.Write(character.WorldPosition.Y); message.Write(character.Info.Job.Name); } diff --git a/Subsurface/Source/Utils/Rand.cs b/Subsurface/Source/Utils/Rand.cs index e62bcd7cf..20dcaccf5 100644 --- a/Subsurface/Source/Utils/Rand.cs +++ b/Subsurface/Source/Utils/Rand.cs @@ -18,14 +18,12 @@ namespace Barotrauma public static float Range(float minimum, float maximum, bool local = true) { - return (float)(local ? localRandom : syncedRandom).NextDouble() * (maximum - minimum) + minimum; - + return (float)(local ? localRandom : syncedRandom).NextDouble() * (maximum - minimum) + minimum; } public static int Range(int minimum, int maximum, bool local = true) { - return (local ? localRandom : syncedRandom).Next(maximum - minimum) + minimum; - + return (local ? localRandom : syncedRandom).Next(maximum - minimum) + minimum; } public static int Int(int max = int.MaxValue, bool local = true) diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index aa65a3a5f06dd10b5ec60ea02929f8c71dbbe8e6..b1453c56c0baf09072d1b5decdba21df79f00ea3 100644 GIT binary patch delta 3630 zcmchZ4OEm>8pr3k_YTYl%pfzshzc*mC@82<{8d)6B{Zt}bCyOn z8-fIo0WqfEQAFParo*us_++KnMT=y%H9`Ev3@Ww;L=S$l%KD)9BqHyFHv@7TWIL#5 z^Q>(tIlh0*;iP(-&u)%vMSG7-5o7zAL-d^|0`oi=qjy~U=o9>d8)Y^=%TnZr^S*Ex-s4`$P81LTcc9t>L_1b<7`*M|eO5LOdXMdoxwlr+kX-4op?vcRF?MQ$E=oQdOPiWoqiBB2{KFyE=E8 zXKv6sg`ri^38JGaI8033QAFWs^%Vglu$y;Kcm`=nQky7@z-H>AjaoI?nzffskb2>6 z+bEUw=g35(Bt!>?ZqP1ahPDOcU=zykW~I)dSpNnb7k;v5eyY*5N6aGCw8=Kk7`Kgz zBIuBMB1{P^%cAr!<@+wjnmci{_2{q~azEq|NYxdlGDm-CkHS-GQ8yYiTCIAQVxq!u zHpAHs)HZ{BwiiuBzMBlA@I%t%P>Y9qy?mb zm%&_^9>@p5CK+_6iV4u0WbJZjcKU=*`H*6Jdt@_(a5GP%{y%oXHw@QncCoJG;;P@w>+oE2|?18G{np z2Oj++V(OBxy}&5QVr|xjFs=CSYwcYs%IsTar*Q)2O8*Y|8}Ko9@d~6_cxLYYz3}AX zCY(ziI~HfqDbYjv6qX#*w;oXOBhT>f?Jc!HkGSUAkIBtz>k?`5qD z9;VyWfvJuWM*U${!5g0EnxQS_xP_s!{07yQ$_5$_bg;+!={|Hl!~8bGzmw}E=Ju_C z=(i$}CM?zb%~ZiMHr6QUWNn^?bkbzw5Zv)Ytb$?!~Qydy0>}C}zb)*|LWqe_O zeJx}9z1*fx5lmmm9epEW+Q%*_Gv0eLeOyLP{{8jCr>OFo-KpA- z@)BcmA>TsQg9}o(F4y<)KtrzhZOs1Zu}k9)CWNbgb;`ffUZRk8lV*UzexgLu55ZN?!cuEKd-iZqOeEQ73qG)t+~q7qAa zQd}KMONZ|`pcP;VcMyj;~*&~UYTjz}~@T|DHJ!7Dwg;8C)vSFU3H)u{1ek_t{og}03t zIDUu7RBa>p07WDDU|Ou`dOkyG*Vw(Pb%5PV>l;S!RO17ia}b4VM2J+u2p-Z$3kR)K z!5(@*6*%k;75ai7aO+pO?!I#EvTF|QU9PsK4^!)xpvJ4t^A#%lVe4RZv_8^djGQ2j zao7LoD9y9@2}fyG!vFIqwTm64xftWzwIYgzyXg&zajvP{k~%@;EM5{h^7Q+UpHP+0 zQoK6VLta-hPJbx2{yt8;$s%2`xvZGU39)|bEO-;;{Mdw{k07Q6?Vm%ML!X6Q3EQlg z9_Xovw1HdY*4TvLrD$=0v*1;bfQV6XJSjM2np5@eUpi$1+^Dv1o*^=P?X&8+7^nTk0QsTxE%kwROK04hLLf*I3I2JzcgQ~lvZ1|TK*6PjOo?lIrl}fa~&r6 zes;|DeVZL~3E#`k)jv5q81#a)dy>DKA=k5gGPKMpXL;g#^JA{zKgiE=;qv|hDK)#* zd?QWW@a{)3$;J|VyjF{2^vzezg-af@`ID~~tYAk5Yj55%qw{w&GE~Y1T-C?iyqadK z;0``sHD=?(S-ws@9jz{TIpRju{Y+$pF}ssDlDkQR{Q)x&CPHSe#EZx?>O1Yfx%&cZek#CK{gFI0^m+mjOa51a29kev3; zn*;BBxqaXlPoj!?^U+hRf+ZqfC9Su+jOY^a*~MlJoecakuvY*phyanm2JFCL1ok>R GuJ{L%)+RIn delta 3794 zcmcIm4RF-O6~DK;m)u>FOC%Q((vTdNBP4ui!bd>lBLT!D4JJX8;GHEVh4QGMT~vw=kK?sp`H&npVH?3o@6r%_=DK%@@lktl>*B zfXuzgWIFHbXBmG(AB^q=?!>ayz+&Hg^*T-WWtrpE1^j%4W;Y%8&9^Rgya4s1z#y0x zf_DSeVy?NeY4%0$Y49FF)s_Tx-dLJsnRJ!^so(e)C&*V|PV4c0gR$8a-nnWu-Bk7b zBMob9T|}X(s(8J%MHQ33l@bz8;tZRxe-1bWm;fXKoY_jF)ECh3+*Wd1??xn6K)#FD zv{DL1@QzlxjruX2rudARP|k$%moSe5n}7j8GVlPVvEavn#hiPZQoF;!51po@s8tXW z7CXSVan)&xjVguxB252gHkq2Z9`*z0Vrs;p2z(Hzhe-}rEdkeKJ`HGs`4nmhMGIk1 zfjk5H_aILbY%f;XVma~TV&yWoLpFpTE>`gwwJ_U`>6c(5XrF^iu`Jw}1F0BW0Ld@G zJoiJ;mpn|f*I5;{e- zJIC}0I+S)Ehk#CS?m(5lt$>1e_=9pH?+vQ4+8dN!3f@J|f-R0C3&d$S> zYNaQo$&`eX^6rTu&Q}&4%bvqj#1q?TsIuV_zLMxvh#dyF@grL}zj=g4d@bqbOkuf9 zle0XXk5yRH^zB}HE5ql^SK95NF4E3AoHDRk3a;H`nV=_ZrGhX@;HQHWFYXZ>2-3KO ztvJbK1gjdn8hjLNd`w5$C$qlSfMKf8Zb8Gyj4?zWi})W z@Gbb5CbumSqe5Uk@sb^srrq1AImI8Ol^2iE^Tsy?Y0Nbb((U%DgNzgfkza3YyoYb! zScl#vVGphnPT_O*L1_L-&9TAT)d7lmZ~vUxXZs%ZtV!Qn-+5!Phv&aQz4_B3<=7w+ z0%wHa`Q_n#b>BqsVQh6|0)=#+7WFZ4Rjll?H#hu0b;-EF zx7Ve-|Ftd+N0^PeGy%`{^15Vfu?*FdBTH1$f0rjidF}G_kM8oMjPk_Kl&G9V!Y1j5RI|ixSED>%;(`zI;TeUrlk zdDE@0VY(2iV?ZyA-vKTFmB1pzEdr*7t5M*ofCAE?i-r9=(9gqoH}CF{@x2E?H3QQq z@Cfj~fZ@bvI%IFh4wx51J`A#Ku;G#uI;FEu2$~K^!yqjMZv&P?_B5At%J?+cU9dwH z1@R}qcBsyS&5-#q&If0jcvYuN?sYT9bD%2%kA|*5@UBkTdtesk??dhd4gm$gQt0=B zUjUrYp9QZW9lAq`#6XP@G@UE77|m^E%Bk;tME)V1%9(DLck!5dn^XVnab=~L)}oQU zrgY8u?cI4B-_&7|w=#uAWOCz|ww%BsY4ds0@cmAR778qv!smSvvze-e{PUDsyPraV z3I0N%OQ}E@p8$;dy#%}z@B)EVGAUyH?9ZBKk4zgGw{Q;AVv5twb|fWNJZc@F2h_=T zqy5nW-rB_mQV-%Dm!4z98))$ux5SU>W9tt&rpB76XYP_~tvxSm8sTJzq}!h^UF=#; zQ+=NHVv7-QqvN^c$al8A$hX&#<@21Ire<8JIX754+vF*8a1uJMn8=h(8LfHsHCElc zr`Yp%3(qJe2YYT+D|;^Q!R2}AYhlwlv>`l9mu*(h6aV$C@SC}E9u47xc`{LZyQDWF zctGV6=T@i(qYJG^lXpJ+(5o+J-u>fg5vy4LS>*?8YOw!|d^u+Ssc|jY=c-mV9)6&7 z+uN_lc5kTPJ|l+^&o~#}pL33w9endn^+d$7!V769U+cg2r2`9jUA8qtpWdnBDKJ{u ze7R#|Ij4dw{HKYc4-dDfDLpydXi+)%*Lc$0pHEbW+w@J7)k$gpPWd%{#O3)k7Qr*} z$q4cF^C{t4`D85RwhrmIDxS0z~fQ`rm9}SJh^~k z_C1!LIe6GBM?b9#efFc8lI`8EnrrgqES}$H8KeizQvZ(fxoT=H4w~Sy>)7mB^~KE&`7~ce-mfxR8N*= zUm^Cqq*nT0CU=87kU~bjne!t|rsw!v6lM5oH{KTvs!2kOFkR|*!;GrlY3D`TRepC5 z>))X!TFC|Jkjp*OEMBlfEj6!z@UCumTw5*D)D_LFc_TJ!{?0w@#eVnd?zX4TeR?U{ z@|c{kHu5*ANxpp|Q+t~5xxzQ1nJzm-+_{A^*u8~{&6BbJdOo*>2I&o3sFcud{mOM% V0cIc!2nQ^H6|ia7;fR)7{sS{fZBYOK