diff options
author | Melanie | 2011-10-11 22:42:18 +0100 |
---|---|---|
committer | Melanie | 2011-10-11 22:42:18 +0100 |
commit | 652c59c0a9e7ac16127f0358e91fd216576c0ad0 (patch) | |
tree | e967460e6e83aa88bd49865af312b1b5738507fd | |
parent | Merge commit '241e07d006fad1b54e088d8a9ddede0b98a1e800' into bigmerge (diff) | |
parent | Reinstate option to land an npc when it reaches a target. (diff) | |
download | opensim-SC-652c59c0a9e7ac16127f0358e91fd216576c0ad0.zip opensim-SC-652c59c0a9e7ac16127f0358e91fd216576c0ad0.tar.gz opensim-SC-652c59c0a9e7ac16127f0358e91fd216576c0ad0.tar.bz2 opensim-SC-652c59c0a9e7ac16127f0358e91fd216576c0ad0.tar.xz |
Merge commit 'd358125cac4e01194dae4b1f0bc9afc87e463f76' into bigmerge
12 files changed, 28 insertions, 90 deletions
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs index 1023108..b53806c 100644 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs +++ b/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs | |||
@@ -169,7 +169,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory.Tests | |||
169 | float y = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Y]); | 169 | float y = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Y]); |
170 | float z = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Z]); | 170 | float z = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Z]); |
171 | Vector3 vector = new Vector3(x, y, z); | 171 | Vector3 vector = new Vector3(x, y, z); |
172 | presence.MoveToTarget(vector, false); | 172 | presence.MoveToTarget(vector, false, false); |
173 | } | 173 | } |
174 | catch (Exception e) | 174 | catch (Exception e) |
175 | { | 175 | { |
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index ee3d6b6..cdd50d0 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs | |||
@@ -940,7 +940,7 @@ namespace OpenSim.Framework | |||
940 | event ScriptReset OnScriptReset; | 940 | event ScriptReset OnScriptReset; |
941 | event GetScriptRunning OnGetScriptRunning; | 941 | event GetScriptRunning OnGetScriptRunning; |
942 | event SetScriptRunning OnSetScriptRunning; | 942 | event SetScriptRunning OnSetScriptRunning; |
943 | event Action<Vector3, bool> OnAutoPilotGo; | 943 | event Action<Vector3, bool, bool> OnAutoPilotGo; |
944 | 944 | ||
945 | event TerrainUnacked OnUnackedTerrain; | 945 | event TerrainUnacked OnUnackedTerrain; |
946 | event ActivateGesture OnActivateGesture; | 946 | event ActivateGesture OnActivateGesture; |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 37024fd..243dad5 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -232,7 +232,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
232 | public event ScriptReset OnScriptReset; | 232 | public event ScriptReset OnScriptReset; |
233 | public event GetScriptRunning OnGetScriptRunning; | 233 | public event GetScriptRunning OnGetScriptRunning; |
234 | public event SetScriptRunning OnSetScriptRunning; | 234 | public event SetScriptRunning OnSetScriptRunning; |
235 | public event Action<Vector3, bool> OnAutoPilotGo; | 235 | public event Action<Vector3, bool, bool> OnAutoPilotGo; |
236 | public event TerrainUnacked OnUnackedTerrain; | 236 | public event TerrainUnacked OnUnackedTerrain; |
237 | public event ActivateGesture OnActivateGesture; | 237 | public event ActivateGesture OnActivateGesture; |
238 | public event DeactivateGesture OnDeactivateGesture; | 238 | public event DeactivateGesture OnDeactivateGesture; |
@@ -11756,9 +11756,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11756 | locy = Convert.ToSingle(args[1]) - (float)regionY; | 11756 | locy = Convert.ToSingle(args[1]) - (float)regionY; |
11757 | locz = Convert.ToSingle(args[2]); | 11757 | locz = Convert.ToSingle(args[2]); |
11758 | 11758 | ||
11759 | Action<Vector3, bool> handlerAutoPilotGo = OnAutoPilotGo; | 11759 | Action<Vector3, bool, bool> handlerAutoPilotGo = OnAutoPilotGo; |
11760 | if (handlerAutoPilotGo != null) | 11760 | if (handlerAutoPilotGo != null) |
11761 | handlerAutoPilotGo(new Vector3(locx, locy, locz), false); | 11761 | handlerAutoPilotGo(new Vector3(locx, locy, locz), false, false); |
11762 | } | 11762 | } |
11763 | 11763 | ||
11764 | /// <summary> | 11764 | /// <summary> |
diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index 3b740e2..54c1c21 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs | |||
@@ -222,7 +222,7 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
222 | public event ScriptReset OnScriptReset; | 222 | public event ScriptReset OnScriptReset; |
223 | public event GetScriptRunning OnGetScriptRunning; | 223 | public event GetScriptRunning OnGetScriptRunning; |
224 | public event SetScriptRunning OnSetScriptRunning; | 224 | public event SetScriptRunning OnSetScriptRunning; |
225 | public event Action<Vector3, bool> OnAutoPilotGo; | 225 | public event Action<Vector3, bool, bool> OnAutoPilotGo; |
226 | 226 | ||
227 | public event TerrainUnacked OnUnackedTerrain; | 227 | public event TerrainUnacked OnUnackedTerrain; |
228 | 228 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index fc89b2a..01ab199 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -5447,10 +5447,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
5447 | for (int i = 0; i < 5; i++) | 5447 | for (int i = 0; i < 5; i++) |
5448 | presence.PhysicsActor.IsColliding = true; | 5448 | presence.PhysicsActor.IsColliding = true; |
5449 | 5449 | ||
5450 | // Vector3 targetPos = presence.MoveToPositionTarget; | 5450 | if (presence.LandAtTarget) |
5451 | // if (m_avatars[presence.UUID].LandAtTarget) | 5451 | presence.PhysicsActor.Flying = false; |
5452 | // presence.PhysicsActor.Flying = false; | ||
5453 | 5452 | ||
5453 | // Vector3 targetPos = presence.MoveToPositionTarget; | ||
5454 | // float terrainHeight = (float)presence.Scene.Heightmap[(int)targetPos.X, (int)targetPos.Y]; | 5454 | // float terrainHeight = (float)presence.Scene.Heightmap[(int)targetPos.X, (int)targetPos.Y]; |
5455 | // if (targetPos.Z - terrainHeight < 0.2) | 5455 | // if (targetPos.Z - terrainHeight < 0.2) |
5456 | // { | 5456 | // { |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 5e9cb32..6ff5364 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -1939,7 +1939,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1939 | ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); | 1939 | ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); |
1940 | if (avatar != null) | 1940 | if (avatar != null) |
1941 | { | 1941 | { |
1942 | avatar.MoveToTarget(target, false); | 1942 | avatar.MoveToTarget(target, false, false); |
1943 | } | 1943 | } |
1944 | } | 1944 | } |
1945 | else | 1945 | else |
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 91052ec..09a8bb7 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs | |||
@@ -236,6 +236,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
236 | public Vector3 MoveToPositionTarget { get; private set; } | 236 | public Vector3 MoveToPositionTarget { get; private set; } |
237 | private Quaternion m_offsetRotation = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f); | 237 | private Quaternion m_offsetRotation = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f); |
238 | 238 | ||
239 | /// <summary> | ||
240 | /// Controls whether an avatar automatically moving to a target will land when it gets there (if flying). | ||
241 | /// </summary> | ||
242 | public bool LandAtTarget { get; private set; } | ||
243 | |||
239 | private bool m_followCamAuto; | 244 | private bool m_followCamAuto; |
240 | 245 | ||
241 | private int m_movementUpdateCount; | 246 | private int m_movementUpdateCount; |
@@ -1829,7 +1834,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1829 | /// This is to allow movement to targets that are known to be on an elevated platform with a continuous path | 1834 | /// This is to allow movement to targets that are known to be on an elevated platform with a continuous path |
1830 | /// from start to finish. | 1835 | /// from start to finish. |
1831 | /// </param> | 1836 | /// </param> |
1832 | public void MoveToTarget(Vector3 pos, bool noFly) | 1837 | /// <param name="landAtTarget"> |
1838 | /// If true and the avatar starts flying during the move then land at the target. | ||
1839 | /// </param> | ||
1840 | public void MoveToTarget(Vector3 pos, bool noFly, bool landAtTarget) | ||
1833 | { | 1841 | { |
1834 | m_log.DebugFormat( | 1842 | m_log.DebugFormat( |
1835 | "[SCENE PRESENCE]: Avatar {0} received request to move to position {1} in {2}", | 1843 | "[SCENE PRESENCE]: Avatar {0} received request to move to position {1} in {2}", |
@@ -1868,6 +1876,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1868 | else if (pos.Z > terrainHeight) | 1876 | else if (pos.Z > terrainHeight) |
1869 | PhysicsActor.Flying = true; | 1877 | PhysicsActor.Flying = true; |
1870 | 1878 | ||
1879 | LandAtTarget = landAtTarget; | ||
1871 | MovingToTarget = true; | 1880 | MovingToTarget = true; |
1872 | MoveToPositionTarget = pos; | 1881 | MoveToPositionTarget = pos; |
1873 | 1882 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs index 5a85d7f..64c36ff 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs | |||
@@ -85,7 +85,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
85 | Assert.That(sp.AbsolutePosition, Is.EqualTo(startPos)); | 85 | Assert.That(sp.AbsolutePosition, Is.EqualTo(startPos)); |
86 | 86 | ||
87 | Vector3 targetPos = startPos + new Vector3(0, 10, 0); | 87 | Vector3 targetPos = startPos + new Vector3(0, 10, 0); |
88 | sp.MoveToTarget(targetPos, false); | 88 | sp.MoveToTarget(targetPos, false, false); |
89 | 89 | ||
90 | Assert.That(sp.AbsolutePosition, Is.EqualTo(startPos)); | 90 | Assert.That(sp.AbsolutePosition, Is.EqualTo(startPos)); |
91 | Assert.That( | 91 | Assert.That( |
@@ -110,7 +110,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
110 | // Try a second movement | 110 | // Try a second movement |
111 | startPos = sp.AbsolutePosition; | 111 | startPos = sp.AbsolutePosition; |
112 | targetPos = startPos + new Vector3(10, 0, 0); | 112 | targetPos = startPos + new Vector3(10, 0, 0); |
113 | sp.MoveToTarget(targetPos, false); | 113 | sp.MoveToTarget(targetPos, false, false); |
114 | 114 | ||
115 | Assert.That(sp.AbsolutePosition, Is.EqualTo(startPos)); | 115 | Assert.That(sp.AbsolutePosition, Is.EqualTo(startPos)); |
116 | Assert.That( | 116 | Assert.That( |
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 00b1c1e..c92f121 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs | |||
@@ -806,7 +806,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server | |||
806 | public event ScriptReset OnScriptReset; | 806 | public event ScriptReset OnScriptReset; |
807 | public event GetScriptRunning OnGetScriptRunning; | 807 | public event GetScriptRunning OnGetScriptRunning; |
808 | public event SetScriptRunning OnSetScriptRunning; | 808 | public event SetScriptRunning OnSetScriptRunning; |
809 | public event Action<Vector3, bool> OnAutoPilotGo; | 809 | public event Action<Vector3, bool, bool> OnAutoPilotGo; |
810 | public event TerrainUnacked OnUnackedTerrain; | 810 | public event TerrainUnacked OnUnackedTerrain; |
811 | public event ActivateGesture OnActivateGesture; | 811 | public event ActivateGesture OnActivateGesture; |
812 | public event DeactivateGesture OnDeactivateGesture; | 812 | public event DeactivateGesture OnDeactivateGesture; |
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 4f831a4..253fdee 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs | |||
@@ -37,11 +37,6 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
37 | { | 37 | { |
38 | public class NPCAvatar : IClientAPI | 38 | public class NPCAvatar : IClientAPI |
39 | { | 39 | { |
40 | /// <summary> | ||
41 | /// Signal whether the avatar should land when it reaches a move target | ||
42 | /// </summary> | ||
43 | public bool LandAtTarget { get; set; } | ||
44 | |||
45 | private readonly string m_firstname; | 40 | private readonly string m_firstname; |
46 | private readonly string m_lastname; | 41 | private readonly string m_lastname; |
47 | private readonly Vector3 m_startPos; | 42 | private readonly Vector3 m_startPos; |
@@ -333,7 +328,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
333 | public event ScriptReset OnScriptReset; | 328 | public event ScriptReset OnScriptReset; |
334 | public event GetScriptRunning OnGetScriptRunning; | 329 | public event GetScriptRunning OnGetScriptRunning; |
335 | public event SetScriptRunning OnSetScriptRunning; | 330 | public event SetScriptRunning OnSetScriptRunning; |
336 | public event Action<Vector3, bool> OnAutoPilotGo; | 331 | public event Action<Vector3, bool, bool> OnAutoPilotGo; |
337 | 332 | ||
338 | public event TerrainUnacked OnUnackedTerrain; | 333 | public event TerrainUnacked OnUnackedTerrain; |
339 | 334 | ||
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index 6282245..bcd9e94 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs | |||
@@ -53,78 +53,13 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
53 | if (config != null && config.GetBoolean("Enabled", false)) | 53 | if (config != null && config.GetBoolean("Enabled", false)) |
54 | { | 54 | { |
55 | scene.RegisterModuleInterface<INPCModule>(this); | 55 | scene.RegisterModuleInterface<INPCModule>(this); |
56 | // scene.EventManager.OnSignificantClientMovement += HandleOnSignificantClientMovement; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | public void HandleOnSignificantClientMovement(ScenePresence presence) | ||
61 | { | ||
62 | lock (m_avatars) | ||
63 | { | ||
64 | if (m_avatars.ContainsKey(presence.UUID) && presence.MovingToTarget) | ||
65 | { | ||
66 | double distanceToTarget = Util.GetDistanceTo(presence.AbsolutePosition, presence.MoveToPositionTarget); | ||
67 | // m_log.DebugFormat( | ||
68 | // "[NPC MODULE]: Abs pos of {0} is {1}, target {2}, distance {3}", | ||
69 | // presence.Name, presence.AbsolutePosition, presence.MoveToPositionTarget, distanceToTarget); | ||
70 | |||
71 | // Check the error term of the current position in relation to the target position | ||
72 | if (distanceToTarget <= ScenePresence.SIGNIFICANT_MOVEMENT) | ||
73 | { | ||
74 | // We are close enough to the target | ||
75 | m_log.DebugFormat("[NPC MODULE]: Stopping movement of npc {0}", presence.Name); | ||
76 | |||
77 | presence.Velocity = Vector3.Zero; | ||
78 | presence.AbsolutePosition = presence.MoveToPositionTarget; | ||
79 | presence.ResetMoveToTarget(); | ||
80 | |||
81 | if (presence.PhysicsActor.Flying) | ||
82 | { | ||
83 | // A horrible hack to stop the NPC dead in its tracks rather than having them overshoot | ||
84 | // the target if flying. | ||
85 | // We really need to be more subtle (slow the avatar as it approaches the target) or at | ||
86 | // least be able to set collision status once, rather than 5 times to give it enough | ||
87 | // weighting so that that PhysicsActor thinks it really is colliding. | ||
88 | for (int i = 0; i < 5; i++) | ||
89 | presence.PhysicsActor.IsColliding = true; | ||
90 | |||
91 | // Vector3 targetPos = presence.MoveToPositionTarget; | ||
92 | if (m_avatars[presence.UUID].LandAtTarget) | ||
93 | presence.PhysicsActor.Flying = false; | ||
94 | |||
95 | // float terrainHeight = (float)presence.Scene.Heightmap[(int)targetPos.X, (int)targetPos.Y]; | ||
96 | // if (targetPos.Z - terrainHeight < 0.2) | ||
97 | // { | ||
98 | // presence.PhysicsActor.Flying = false; | ||
99 | // } | ||
100 | } | ||
101 | |||
102 | // m_log.DebugFormat( | ||
103 | // "[NPC MODULE]: AgentControlFlags {0}, MovementFlag {1} for {2}", | ||
104 | // presence.AgentControlFlags, presence.MovementFlag, presence.Name); | ||
105 | } | ||
106 | else | ||
107 | { | ||
108 | // m_log.DebugFormat( | ||
109 | // "[NPC MODULE]: Updating npc {0} at {1} for next movement to {2}", | ||
110 | // presence.Name, presence.AbsolutePosition, presence.MoveToPositionTarget); | ||
111 | |||
112 | Vector3 agent_control_v3 = new Vector3(); | ||
113 | presence.HandleMoveToTargetUpdate(ref agent_control_v3); | ||
114 | presence.AddNewMovement(agent_control_v3); | ||
115 | } | ||
116 | // | ||
117 | //// presence.DoMoveToPositionUpdate((0, presence.MoveToPositionTarget, null); | ||
118 | |||
119 | // | ||
120 | // | ||
121 | |||
122 | } | ||
123 | } | 56 | } |
124 | } | 57 | } |
125 | 58 | ||
126 | public bool IsNPC(UUID agentId, Scene scene) | 59 | public bool IsNPC(UUID agentId, Scene scene) |
127 | { | 60 | { |
61 | // FIXME: This implementation could not just use the ScenePresence.PresenceType (and callers could inspect | ||
62 | // that directly). | ||
128 | ScenePresence sp = scene.GetScenePresence(agentId); | 63 | ScenePresence sp = scene.GetScenePresence(agentId); |
129 | if (sp == null || sp.IsChildAgent) | 64 | if (sp == null || sp.IsChildAgent) |
130 | return false; | 65 | return false; |
@@ -218,8 +153,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
218 | "[NPC MODULE]: Moving {0} to {1} in {2}, noFly {3}, landAtTarget {4}", | 153 | "[NPC MODULE]: Moving {0} to {1} in {2}, noFly {3}, landAtTarget {4}", |
219 | sp.Name, pos, scene.RegionInfo.RegionName, noFly, landAtTarget); | 154 | sp.Name, pos, scene.RegionInfo.RegionName, noFly, landAtTarget); |
220 | 155 | ||
221 | m_avatars[agentID].LandAtTarget = landAtTarget; | 156 | sp.MoveToTarget(pos, noFly, landAtTarget); |
222 | sp.MoveToTarget(pos, noFly); | ||
223 | 157 | ||
224 | return true; | 158 | return true; |
225 | } | 159 | } |
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 014f7f6..b4f521f 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs | |||
@@ -234,7 +234,7 @@ namespace OpenSim.Tests.Common.Mock | |||
234 | public event ScriptReset OnScriptReset; | 234 | public event ScriptReset OnScriptReset; |
235 | public event GetScriptRunning OnGetScriptRunning; | 235 | public event GetScriptRunning OnGetScriptRunning; |
236 | public event SetScriptRunning OnSetScriptRunning; | 236 | public event SetScriptRunning OnSetScriptRunning; |
237 | public event Action<Vector3, bool> OnAutoPilotGo; | 237 | public event Action<Vector3, bool, bool> OnAutoPilotGo; |
238 | 238 | ||
239 | public event TerrainUnacked OnUnackedTerrain; | 239 | public event TerrainUnacked OnUnackedTerrain; |
240 | 240 | ||