diff options
author | Melanie | 2010-01-21 23:48:11 +0000 |
---|---|---|
committer | Melanie | 2010-01-21 23:48:11 +0000 |
commit | d2e17f4ffb3bbd4e377152bef097d47d481c6c5c (patch) | |
tree | 82603908ff006d9c61d28c56ea8b5296933223fc /OpenSim/Region | |
parent | Merge branch 'master' into careminster (diff) | |
parent | Add glue for llSetVehicleFlags(), llRemoveVehicleFlags(). ChODE: Add associat... (diff) | |
download | opensim-SC_OLD-d2e17f4ffb3bbd4e377152bef097d47d481c6c5c.zip opensim-SC_OLD-d2e17f4ffb3bbd4e377152bef097d47d481c6c5c.tar.gz opensim-SC_OLD-d2e17f4ffb3bbd4e377152bef097d47d481c6c5c.tar.bz2 opensim-SC_OLD-d2e17f4ffb3bbd4e377152bef097d47d481c6c5c.tar.xz |
Merge branch 'master' of ssh://melanie@3dhosting.de/var/git/careminster into careminster
Diffstat (limited to 'OpenSim/Region')
16 files changed, 284 insertions, 98 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index a7c14cf..04be9fc 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | |||
@@ -109,7 +109,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
109 | 109 | ||
110 | // TODO: This needs to be persisted in next XML version update! | 110 | // TODO: This needs to be persisted in next XML version update! |
111 | [XmlIgnore] | 111 | [XmlIgnore] |
112 | public readonly int[] PayPrice = {-2,-2,-2,-2,-2}; | 112 | public int[] PayPrice = {-2,-2,-2,-2,-2}; |
113 | [XmlIgnore] | 113 | [XmlIgnore] |
114 | public PhysicsActor PhysActor; | 114 | public PhysicsActor PhysActor; |
115 | 115 | ||
@@ -2963,7 +2963,23 @@ namespace OpenSim.Region.Framework.Scenes | |||
2963 | PhysActor.VehicleRotationParam(param, rotation); | 2963 | PhysActor.VehicleRotationParam(param, rotation); |
2964 | } | 2964 | } |
2965 | } | 2965 | } |
2966 | 2966 | ||
2967 | public void SetVehicleFlags(int flags) | ||
2968 | { | ||
2969 | if (PhysActor != null) | ||
2970 | { | ||
2971 | PhysActor.VehicleFlagsSet(flags); | ||
2972 | } | ||
2973 | } | ||
2974 | |||
2975 | public void RemoveVehicleFlags(int flags) | ||
2976 | { | ||
2977 | if (PhysActor != null) | ||
2978 | { | ||
2979 | PhysActor.VehicleFlagsRemove(flags); | ||
2980 | } | ||
2981 | } | ||
2982 | |||
2967 | public void SetGroup(UUID groupID, IClientAPI client) | 2983 | public void SetGroup(UUID groupID, IClientAPI client) |
2968 | { | 2984 | { |
2969 | _groupID = groupID; | 2985 | _groupID = groupID; |
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs index 31366db..25b9099 100644 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs +++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs | |||
@@ -184,7 +184,17 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin | |||
184 | { | 184 | { |
185 | 185 | ||
186 | } | 186 | } |
187 | |||
188 | public override void VehicleFlagsSet(int flags) | ||
189 | { | ||
190 | |||
191 | } | ||
192 | |||
193 | public override void VehicleFlagsRemove(int flags) | ||
194 | { | ||
187 | 195 | ||
196 | } | ||
197 | |||
188 | public override void SetVolumeDetect(int param) | 198 | public override void SetVolumeDetect(int param) |
189 | { | 199 | { |
190 | 200 | ||
diff --git a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs index a3344dd..120d040 100644 --- a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs +++ b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs | |||
@@ -361,7 +361,17 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
361 | { | 361 | { |
362 | 362 | ||
363 | } | 363 | } |
364 | |||
365 | public override void VehicleFlagsSet(int flags) | ||
366 | { | ||
367 | |||
368 | } | ||
369 | |||
370 | public override void VehicleFlagsRemove(int flags) | ||
371 | { | ||
364 | 372 | ||
373 | } | ||
374 | |||
365 | public override void SetVolumeDetect(int param) | 375 | public override void SetVolumeDetect(int param) |
366 | { | 376 | { |
367 | 377 | ||
diff --git a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs index 9603ea4..f430def 100644 --- a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs +++ b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs | |||
@@ -396,7 +396,17 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
396 | { | 396 | { |
397 | //TODO: | 397 | //TODO: |
398 | } | 398 | } |
399 | |||
400 | public override void VehicleFlagsSet(int flags) | ||
401 | { | ||
402 | |||
403 | } | ||
404 | |||
405 | public override void VehicleFlagsRemove(int flags) | ||
406 | { | ||
399 | 407 | ||
408 | } | ||
409 | |||
400 | public override void SetVolumeDetect(int param) | 410 | public override void SetVolumeDetect(int param) |
401 | { | 411 | { |
402 | //TODO: GhostObject | 412 | //TODO: GhostObject |
diff --git a/OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs b/OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs index d5d146e..9113ebe 100644 --- a/OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs +++ b/OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs | |||
@@ -984,7 +984,17 @@ namespace OpenSim.Region.Physics.BulletXPlugin | |||
984 | { | 984 | { |
985 | 985 | ||
986 | } | 986 | } |
987 | |||
988 | public override void VehicleFlagsSet(int flags) | ||
989 | { | ||
990 | |||
991 | } | ||
992 | |||
993 | public override void VehicleFlagsRemove(int flags) | ||
994 | { | ||
987 | 995 | ||
996 | } | ||
997 | |||
988 | public override void SetVolumeDetect(int param) | 998 | public override void SetVolumeDetect(int param) |
989 | { | 999 | { |
990 | 1000 | ||
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs index aa0acb7..2eb519f 100644 --- a/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs | |||
@@ -733,7 +733,17 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
733 | { | 733 | { |
734 | 734 | ||
735 | } | 735 | } |
736 | |||
737 | public override void VehicleFlagsSet(int flags) | ||
738 | { | ||
736 | 739 | ||
740 | } | ||
741 | |||
742 | public override void VehicleFlagsRemove(int flags) | ||
743 | { | ||
744 | |||
745 | } | ||
746 | |||
737 | public override void SetVolumeDetect(int param) | 747 | public override void SetVolumeDetect(int param) |
738 | { | 748 | { |
739 | 749 | ||
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEDynamics.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEDynamics.cs index ef2dccc..14d5caa 100644 --- a/OpenSim/Region/Physics/ChOdePlugin/ODEDynamics.cs +++ b/OpenSim/Region/Physics/ChOdePlugin/ODEDynamics.cs | |||
@@ -82,13 +82,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
82 | private IntPtr m_body = IntPtr.Zero; | 82 | private IntPtr m_body = IntPtr.Zero; |
83 | // private IntPtr m_jointGroup = IntPtr.Zero; | 83 | // private IntPtr m_jointGroup = IntPtr.Zero; |
84 | // private IntPtr m_aMotor = IntPtr.Zero; | 84 | // private IntPtr m_aMotor = IntPtr.Zero; |
85 | |||
86 | // Correction factors, to match Sl | ||
87 | private static float m_linearVelocityFactor = 0.9f; | ||
88 | private static float m_linearAttackFactor = 0.4f; | ||
89 | private static float m_linearDecayFactor = 0.5f; | ||
90 | private static float m_linearFrictionFactor = 1.2f; | ||
91 | |||
92 | 85 | ||
93 | // Vehicle properties | 86 | // Vehicle properties |
94 | private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind | 87 | private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind |
@@ -103,15 +96,15 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
103 | // LIMIT_ROLL_ONLY | 96 | // LIMIT_ROLL_ONLY |
104 | 97 | ||
105 | // Linear properties | 98 | // Linear properties |
106 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time | 99 | private Vector3 m_linearMotorDirection = Vector3.Zero; // (was m_linearMotorDirectionLASTSET) the (local) Velocity |
107 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL, for max limiting | 100 | //requested by LSL |
108 | private Vector3 m_dir = Vector3.Zero; // velocity applied to body | 101 | private float m_linearMotorTimescale = 0; // Motor Attack rate set by LSL |
109 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; | 102 | private float m_linearMotorDecayTimescale = 0; // Motor Decay rate set by LSL |
110 | private float m_linearMotorDecayTimescale = 0; | 103 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; // General Friction set by LSL |
111 | private float m_linearMotorTimescale = 0; | 104 | |
112 | private Vector3 m_lastLinearVelocityVector = Vector3.Zero; | 105 | private Vector3 m_lLinMotorDVel = Vector3.Zero; // decayed motor |
113 | // private bool m_LinearMotorSetLastFrame = false; | 106 | private Vector3 m_lLinObjectVel = Vector3.Zero; // local frame object velocity |
114 | // private Vector3 m_linearMotorOffset = Vector3.Zero; | 107 | private Vector3 m_wLinObjectVel = Vector3.Zero; // world frame object velocity |
115 | 108 | ||
116 | //Angular properties | 109 | //Angular properties |
117 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | 110 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor |
@@ -241,7 +234,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
241 | break; | 234 | break; |
242 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 235 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
243 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); | 236 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); |
244 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); | 237 | UpdateLinDecay(); |
245 | break; | 238 | break; |
246 | case Vehicle.LINEAR_MOTOR_OFFSET: | 239 | case Vehicle.LINEAR_MOTOR_OFFSET: |
247 | // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); | 240 | // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); |
@@ -273,9 +266,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
273 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 266 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
274 | break; | 267 | break; |
275 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 268 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
276 | pValue *= m_linearVelocityFactor; | 269 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); // velocity requested by LSL, for max limiting |
277 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); // velocity requested by LSL, decayed by time | 270 | UpdateLinDecay(); |
278 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); // velocity requested by LSL, for max limiting | ||
279 | break; | 271 | break; |
280 | case Vehicle.LINEAR_MOTOR_OFFSET: | 272 | case Vehicle.LINEAR_MOTOR_OFFSET: |
281 | // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); | 273 | // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); |
@@ -294,7 +286,17 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
294 | } | 286 | } |
295 | 287 | ||
296 | }//end ProcessRotationVehicleParam | 288 | }//end ProcessRotationVehicleParam |
289 | |||
290 | internal void ProcessFlagsVehicleSet(int flags) | ||
291 | { | ||
292 | m_flags |= (VehicleFlag)flags; | ||
293 | } | ||
297 | 294 | ||
295 | internal void ProcessFlagsVehicleRemove(int flags) | ||
296 | { | ||
297 | m_flags &= ~((VehicleFlag)flags); | ||
298 | } | ||
299 | |||
298 | internal void ProcessTypeChange(Vehicle pType) | 300 | internal void ProcessTypeChange(Vehicle pType) |
299 | { | 301 | { |
300 | // Set Defaults For Type | 302 | // Set Defaults For Type |
@@ -304,7 +306,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
304 | case Vehicle.TYPE_SLED: | 306 | case Vehicle.TYPE_SLED: |
305 | m_linearFrictionTimescale = new Vector3(30, 1, 1000); | 307 | m_linearFrictionTimescale = new Vector3(30, 1, 1000); |
306 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | 308 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); |
307 | m_linearMotorDirection = Vector3.Zero; | 309 | // m_lLinMotorVel = Vector3.Zero; |
308 | m_linearMotorTimescale = 1000; | 310 | m_linearMotorTimescale = 1000; |
309 | m_linearMotorDecayTimescale = 120; | 311 | m_linearMotorDecayTimescale = 120; |
310 | m_angularMotorDirection = Vector3.Zero; | 312 | m_angularMotorDirection = Vector3.Zero; |
@@ -330,7 +332,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
330 | case Vehicle.TYPE_CAR: | 332 | case Vehicle.TYPE_CAR: |
331 | m_linearFrictionTimescale = new Vector3(100, 2, 1000); | 333 | m_linearFrictionTimescale = new Vector3(100, 2, 1000); |
332 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | 334 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); |
333 | m_linearMotorDirection = Vector3.Zero; | 335 | // m_lLinMotorVel = Vector3.Zero; |
334 | m_linearMotorTimescale = 1; | 336 | m_linearMotorTimescale = 1; |
335 | m_linearMotorDecayTimescale = 60; | 337 | m_linearMotorDecayTimescale = 60; |
336 | m_angularMotorDirection = Vector3.Zero; | 338 | m_angularMotorDirection = Vector3.Zero; |
@@ -357,7 +359,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
357 | case Vehicle.TYPE_BOAT: | 359 | case Vehicle.TYPE_BOAT: |
358 | m_linearFrictionTimescale = new Vector3(10, 3, 2); | 360 | m_linearFrictionTimescale = new Vector3(10, 3, 2); |
359 | m_angularFrictionTimescale = new Vector3(10,10,10); | 361 | m_angularFrictionTimescale = new Vector3(10,10,10); |
360 | m_linearMotorDirection = Vector3.Zero; | 362 | // m_lLinMotorVel = Vector3.Zero; |
361 | m_linearMotorTimescale = 5; | 363 | m_linearMotorTimescale = 5; |
362 | m_linearMotorDecayTimescale = 60; | 364 | m_linearMotorDecayTimescale = 60; |
363 | m_angularMotorDirection = Vector3.Zero; | 365 | m_angularMotorDirection = Vector3.Zero; |
@@ -385,7 +387,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
385 | case Vehicle.TYPE_AIRPLANE: | 387 | case Vehicle.TYPE_AIRPLANE: |
386 | m_linearFrictionTimescale = new Vector3(200, 10, 5); | 388 | m_linearFrictionTimescale = new Vector3(200, 10, 5); |
387 | m_angularFrictionTimescale = new Vector3(20, 20, 20); | 389 | m_angularFrictionTimescale = new Vector3(20, 20, 20); |
388 | m_linearMotorDirection = Vector3.Zero; | 390 | // m_lLinMotorVel = Vector3.Zero; |
389 | m_linearMotorTimescale = 2; | 391 | m_linearMotorTimescale = 2; |
390 | m_linearMotorDecayTimescale = 60; | 392 | m_linearMotorDecayTimescale = 60; |
391 | m_angularMotorDirection = Vector3.Zero; | 393 | m_angularMotorDirection = Vector3.Zero; |
@@ -412,7 +414,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
412 | case Vehicle.TYPE_BALLOON: | 414 | case Vehicle.TYPE_BALLOON: |
413 | m_linearFrictionTimescale = new Vector3(5, 5, 5); | 415 | m_linearFrictionTimescale = new Vector3(5, 5, 5); |
414 | m_angularFrictionTimescale = new Vector3(10, 10, 10); | 416 | m_angularFrictionTimescale = new Vector3(10, 10, 10); |
415 | m_linearMotorDirection = Vector3.Zero; | ||
416 | m_linearMotorTimescale = 5; | 417 | m_linearMotorTimescale = 5; |
417 | m_linearMotorDecayTimescale = 60; | 418 | m_linearMotorDecayTimescale = 60; |
418 | m_angularMotorDirection = Vector3.Zero; | 419 | m_angularMotorDirection = Vector3.Zero; |
@@ -453,7 +454,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
453 | if (m_body == IntPtr.Zero || m_type == Vehicle.TYPE_NONE) | 454 | if (m_body == IntPtr.Zero || m_type == Vehicle.TYPE_NONE) |
454 | return; | 455 | return; |
455 | frcount++; // used to limit debug comment output | 456 | frcount++; // used to limit debug comment output |
456 | if (frcount > 100) | 457 | if (frcount > 24) |
457 | frcount = 0; | 458 | frcount = 0; |
458 | 459 | ||
459 | MoveLinear(pTimestep, pParentScene); | 460 | MoveLinear(pTimestep, pParentScene); |
@@ -463,63 +464,90 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
463 | internal void Halt() | 464 | internal void Halt() |
464 | { // Kill all motions, when non-physical | 465 | { // Kill all motions, when non-physical |
465 | m_linearMotorDirection = Vector3.Zero; | 466 | m_linearMotorDirection = Vector3.Zero; |
466 | m_linearMotorDirectionLASTSET = Vector3.Zero; | 467 | m_lLinMotorDVel = Vector3.Zero; |
467 | m_dir = Vector3.Zero; | 468 | m_lLinObjectVel = Vector3.Zero; |
468 | m_lastLinearVelocityVector = Vector3.Zero; | 469 | m_wLinObjectVel = Vector3.Zero; |
469 | m_angularMotorDirection = Vector3.Zero; | 470 | m_angularMotorDirection = Vector3.Zero; |
470 | m_angularMotorVelocity = Vector3.Zero; | 471 | m_angularMotorVelocity = Vector3.Zero; |
471 | m_lastAngularVelocity = Vector3.Zero; | 472 | m_lastAngularVelocity = Vector3.Zero; |
472 | } | 473 | } |
474 | |||
475 | private void UpdateLinDecay() | ||
476 | { | ||
477 | if (Math.Abs(m_linearMotorDirection.X) > Math.Abs(m_lLinMotorDVel.X)) m_lLinMotorDVel.X = m_linearMotorDirection.X; | ||
478 | if (Math.Abs(m_linearMotorDirection.Y) > Math.Abs(m_lLinMotorDVel.Y)) m_lLinMotorDVel.Y = m_linearMotorDirection.Y; | ||
479 | if (Math.Abs(m_linearMotorDirection.Z) > Math.Abs(m_lLinMotorDVel.Z)) m_lLinMotorDVel.Z = m_linearMotorDirection.Z; | ||
480 | } // else let the motor decay on its own | ||
473 | 481 | ||
474 | private void MoveLinear(float pTimestep, OdeScene _pParentScene) | 482 | private void MoveLinear(float pTimestep, OdeScene _pParentScene) |
475 | { | 483 | { |
476 | if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant | 484 | Vector3 acceleration = new Vector3(0f, 0f, 0f); |
477 | { | ||
478 | if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); | ||
479 | 485 | ||
480 | // add drive to body | ||
481 | float linfactor = m_linearMotorTimescale/pTimestep; | ||
482 | // Linear accel | ||
483 | Vector3 addAmount1 = (m_linearMotorDirection/linfactor) * 0.8f; | ||
484 | // Differential accel | ||
485 | Vector3 addAmount2 = ((m_linearMotorDirection - m_lastLinearVelocityVector)/linfactor) * 1.6f; | ||
486 | // SL correction | ||
487 | Vector3 addAmount = (addAmount1 + addAmount2) * m_linearAttackFactor; | ||
488 | m_lastLinearVelocityVector += addAmount; // lastLinearVelocityVector is the current body velocity vector | ||
489 | //if(frcount == 0) Console.WriteLine("AL {0} + AD {1} AS{2} V {3}", addAmount1, addAmount2, addAmount, m_lastLinearVelocityVector); | ||
490 | // This will work temporarily, but we really need to compare speed on an axis | ||
491 | // KF: Limit body velocity to applied velocity? | ||
492 | if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) | ||
493 | m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; | ||
494 | if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) | ||
495 | m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; | ||
496 | if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) | ||
497 | m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; | ||
498 | |||
499 | // decay applied velocity | ||
500 | Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); | ||
501 | //Console.WriteLine("decay: " + decayfraction); | ||
502 | m_linearMotorDirection -= m_linearMotorDirection * decayfraction * m_linearDecayFactor; | ||
503 | //Console.WriteLine("actual: " + m_linearMotorDirection); | ||
504 | } | ||
505 | else | ||
506 | { // requested is not significant | ||
507 | // if what remains of applied is small, zero it. | ||
508 | if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) | ||
509 | m_lastLinearVelocityVector = Vector3.Zero; | ||
510 | } | ||
511 | |||
512 | |||
513 | // convert requested object velocity to world-referenced vector | ||
514 | m_dir = m_lastLinearVelocityVector; | ||
515 | d.Quaternion rot = d.BodyGetQuaternion(Body); | 486 | d.Quaternion rot = d.BodyGetQuaternion(Body); |
516 | Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object | 487 | Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object |
517 | m_dir *= rotq; // apply obj rotation to velocity vector | 488 | Quaternion irotq = Quaternion.Inverse(rotq); |
489 | d.Vector3 velnow = d.BodyGetLinearVel(Body); // this is in world frame | ||
490 | Vector3 vel_now = new Vector3(velnow.X, velnow.Y, velnow.Z); | ||
491 | acceleration = vel_now - m_wLinObjectVel; | ||
492 | m_lLinObjectVel = vel_now * irotq; | ||
493 | |||
494 | if (m_linearMotorDecayTimescale < 300.0f) //setting of 300 or more disables decay rate | ||
495 | { | ||
496 | if ( Vector3.Mag(m_lLinMotorDVel) < 1.0f) | ||
497 | { | ||
498 | float decayfactor = m_linearMotorDecayTimescale/pTimestep; | ||
499 | Vector3 decayAmount = (m_lLinMotorDVel/decayfactor); | ||
500 | m_lLinMotorDVel -= decayAmount; | ||
501 | } | ||
502 | else | ||
503 | { | ||
504 | float decayfactor = 3.0f - (0.57f * (float)Math.Log((double)(m_linearMotorDecayTimescale))); | ||
505 | Vector3 decel = Vector3.Normalize(m_lLinMotorDVel) * decayfactor * pTimestep; | ||
506 | m_lLinMotorDVel -= decel; | ||
507 | } | ||
508 | if (m_lLinMotorDVel.ApproxEquals(Vector3.Zero, 0.01f)) | ||
509 | { | ||
510 | m_lLinMotorDVel = Vector3.Zero; | ||
511 | } | ||
512 | else | ||
513 | { | ||
514 | if (Math.Abs(m_lLinMotorDVel.X) < Math.Abs(m_lLinObjectVel.X)) m_lLinObjectVel.X = m_lLinMotorDVel.X; | ||
515 | if (Math.Abs(m_lLinMotorDVel.Y) < Math.Abs(m_lLinObjectVel.Y)) m_lLinObjectVel.Y = m_lLinMotorDVel.Y; | ||
516 | if (Math.Abs(m_lLinMotorDVel.Z) < Math.Abs(m_lLinObjectVel.Z)) m_lLinObjectVel.Z = m_lLinMotorDVel.Z; | ||
517 | } | ||
518 | } | ||
518 | 519 | ||
519 | // add Gravity and Buoyancy | 520 | if ( (! m_lLinMotorDVel.ApproxEquals(Vector3.Zero, 0.01f)) || (! m_lLinObjectVel.ApproxEquals(Vector3.Zero, 0.01f)) ) |
520 | // KF: So far I have found no good method to combine a script-requested | 521 | { |
521 | // .Z velocity and gravity. Therefore only 0g will used script-requested | 522 | if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); |
522 | // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. | 523 | if (m_linearMotorTimescale < 300.0f) |
524 | { | ||
525 | Vector3 attack_error = m_lLinMotorDVel - m_lLinObjectVel; | ||
526 | float linfactor = m_linearMotorTimescale/pTimestep; | ||
527 | Vector3 attackAmount = (attack_error/linfactor) * 1.3f; | ||
528 | m_lLinObjectVel += attackAmount; | ||
529 | } | ||
530 | if (m_linearFrictionTimescale.X < 300.0f) | ||
531 | { | ||
532 | float fricfactor = m_linearFrictionTimescale.X / pTimestep; | ||
533 | float fricX = m_lLinObjectVel.X / fricfactor; | ||
534 | m_lLinObjectVel.X -= fricX; | ||
535 | } | ||
536 | if (m_linearFrictionTimescale.Y < 300.0f) | ||
537 | { | ||
538 | float fricfactor = m_linearFrictionTimescale.Y / pTimestep; | ||
539 | float fricY = m_lLinObjectVel.Y / fricfactor; | ||
540 | m_lLinObjectVel.Y -= fricY; | ||
541 | } | ||
542 | if (m_linearFrictionTimescale.Z < 300.0f) | ||
543 | { | ||
544 | float fricfactor = m_linearFrictionTimescale.Z / pTimestep; | ||
545 | float fricZ = m_lLinObjectVel.Z / fricfactor; | ||
546 | m_lLinObjectVel.Z -= fricZ; | ||
547 | } | ||
548 | } | ||
549 | m_wLinObjectVel = m_lLinObjectVel * rotq; | ||
550 | // Add Gravity and Buoyancy | ||
523 | Vector3 grav = Vector3.Zero; | 551 | Vector3 grav = Vector3.Zero; |
524 | if(m_VehicleBuoyancy < 1.0f) | 552 | if(m_VehicleBuoyancy < 1.0f) |
525 | { | 553 | { |
@@ -528,10 +556,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
528 | d.Mass objMass; | 556 | d.Mass objMass; |
529 | d.BodyGetMass(Body, out objMass); | 557 | d.BodyGetMass(Body, out objMass); |
530 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | 558 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; |
531 | grav.Z = _pParentScene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); | 559 | grav.Z = _pParentScene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); // Applied later as a force |
532 | // Preserve the current Z velocity | ||
533 | d.Vector3 vel_now = d.BodyGetLinearVel(Body); | ||
534 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity | ||
535 | } // else its 1.0, no gravity. | 560 | } // else its 1.0, no gravity. |
536 | 561 | ||
537 | // Check if hovering | 562 | // Check if hovering |
@@ -567,24 +592,24 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
567 | { | 592 | { |
568 | d.Mass objMass; | 593 | d.Mass objMass; |
569 | d.BodyGetMass(Body, out objMass); | 594 | d.BodyGetMass(Body, out objMass); |
570 | m_dir.Z = - ( (herr0 * pTimestep * 50.0f) / m_VhoverTimescale); | 595 | m_wLinObjectVel.Z = - ( (herr0 * pTimestep * 50.0f) / m_VhoverTimescale); |
571 | //KF: m_VhoverEfficiency is not yet implemented | 596 | //KF: m_VhoverEfficiency is not yet implemented |
572 | } | 597 | } |
573 | else | 598 | else |
574 | { | 599 | { |
575 | m_dir.Z = 0f; | 600 | m_wLinObjectVel.Z = 0f; |
576 | } | 601 | } |
577 | } | 602 | } |
578 | 603 | else | |
604 | { // not hovering, Gravity rules | ||
605 | m_wLinObjectVel.Z = vel_now.Z; | ||
606 | //if(frcount == 0) Console.WriteLine(" Z {0} a.Z {1}", m_wLinObjectVel.Z, acceleration.Z); | ||
607 | } | ||
579 | // Apply velocity | 608 | // Apply velocity |
580 | d.BodySetLinearVel(Body, m_dir.X, m_dir.Y, m_dir.Z); | 609 | d.BodySetLinearVel(Body, m_wLinObjectVel.X, m_wLinObjectVel.Y, m_wLinObjectVel.Z); |
581 | // apply gravity force | 610 | // apply gravity force |
582 | d.BodyAddForce(Body, grav.X, grav.Y, grav.Z); | 611 | d.BodyAddForce(Body, grav.X, grav.Y, grav.Z); |
583 | 612 | //if(frcount == 0) Console.WriteLine("Grav {0}", grav); | |
584 | |||
585 | // apply friction | ||
586 | Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); | ||
587 | m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount * m_linearFrictionFactor; | ||
588 | } // end MoveLinear() | 613 | } // end MoveLinear() |
589 | 614 | ||
590 | private void MoveAngular(float pTimestep) | 615 | private void MoveAngular(float pTimestep) |
@@ -633,7 +658,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
633 | 658 | ||
634 | if(m_verticalAttractionTimescale < 300) | 659 | if(m_verticalAttractionTimescale < 300) |
635 | { | 660 | { |
636 | float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep); | 661 | float VAservo = 0.0167f / (m_verticalAttractionTimescale * pTimestep); |
637 | // get present body rotation | 662 | // get present body rotation |
638 | d.Quaternion rot = d.BodyGetQuaternion(Body); | 663 | d.Quaternion rot = d.BodyGetQuaternion(Body); |
639 | Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); | 664 | Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); |
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs index 6e6b44f..29a3dd9 100644 --- a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs | |||
@@ -2415,7 +2415,17 @@ Console.WriteLine(" JointCreateFixed"); | |||
2415 | { | 2415 | { |
2416 | m_vehicle.ProcessRotationVehicleParam((Vehicle) param, rotation); | 2416 | m_vehicle.ProcessRotationVehicleParam((Vehicle) param, rotation); |
2417 | } | 2417 | } |
2418 | 2418 | ||
2419 | public override void VehicleFlagsSet(int flags) | ||
2420 | { | ||
2421 | m_vehicle.ProcessFlagsVehicleSet(flags); | ||
2422 | } | ||
2423 | |||
2424 | public override void VehicleFlagsRemove(int flags) | ||
2425 | { | ||
2426 | m_vehicle.ProcessFlagsVehicleRemove(flags); | ||
2427 | } | ||
2428 | |||
2419 | public override void SetVolumeDetect(int param) | 2429 | public override void SetVolumeDetect(int param) |
2420 | { | 2430 | { |
2421 | lock (_parent_scene.OdeLock) | 2431 | lock (_parent_scene.OdeLock) |
diff --git a/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs index 60786d4..deb6164 100644 --- a/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs | |||
@@ -229,7 +229,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
229 | 229 | ||
230 | public int bodyFramesAutoDisable = 20; | 230 | public int bodyFramesAutoDisable = 20; |
231 | 231 | ||
232 | protected DateTime m_lastframe = DateTime.UtcNow; | 232 | private DateTime m_lastframe = DateTime.UtcNow; |
233 | 233 | ||
234 | private float[] _watermap; | 234 | private float[] _watermap; |
235 | private bool m_filterCollisions = true; | 235 | private bool m_filterCollisions = true; |
diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs index 9c192ed..f43de48 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs | |||
@@ -208,6 +208,8 @@ namespace OpenSim.Region.Physics.Manager | |||
208 | public abstract void VehicleFloatParam(int param, float value); | 208 | public abstract void VehicleFloatParam(int param, float value); |
209 | public abstract void VehicleVectorParam(int param, Vector3 value); | 209 | public abstract void VehicleVectorParam(int param, Vector3 value); |
210 | public abstract void VehicleRotationParam(int param, Quaternion rotation); | 210 | public abstract void VehicleRotationParam(int param, Quaternion rotation); |
211 | public abstract void VehicleFlagsSet(int flags); | ||
212 | public abstract void VehicleFlagsRemove(int flags); | ||
211 | 213 | ||
212 | public abstract void SetVolumeDetect(int param); // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | 214 | public abstract void SetVolumeDetect(int param); // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more |
213 | 215 | ||
@@ -351,7 +353,17 @@ namespace OpenSim.Region.Physics.Manager | |||
351 | { | 353 | { |
352 | 354 | ||
353 | } | 355 | } |
356 | |||
357 | public override void VehicleFlagsSet(int flags) | ||
358 | { | ||
359 | |||
360 | } | ||
361 | |||
362 | public override void VehicleFlagsRemove(int flags) | ||
363 | { | ||
354 | 364 | ||
365 | } | ||
366 | |||
355 | public override void SetVolumeDetect(int param) | 367 | public override void SetVolumeDetect(int param) |
356 | { | 368 | { |
357 | 369 | ||
diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index a38fccc..b713142 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs | |||
@@ -733,7 +733,17 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
733 | { | 733 | { |
734 | 734 | ||
735 | } | 735 | } |
736 | |||
737 | public override void VehicleFlagsSet(int flags) | ||
738 | { | ||
739 | |||
740 | } | ||
741 | |||
742 | public override void VehicleFlagsRemove(int flags) | ||
743 | { | ||
736 | 744 | ||
745 | } | ||
746 | |||
737 | public override void SetVolumeDetect(int param) | 747 | public override void SetVolumeDetect(int param) |
738 | { | 748 | { |
739 | 749 | ||
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 567fd0e..010d97f 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | |||
@@ -2352,6 +2352,16 @@ Console.WriteLine(" JointCreateFixed"); | |||
2352 | { | 2352 | { |
2353 | m_vehicle.ProcessRotationVehicleParam((Vehicle) param, rotation); | 2353 | m_vehicle.ProcessRotationVehicleParam((Vehicle) param, rotation); |
2354 | } | 2354 | } |
2355 | |||
2356 | public override void VehicleFlagsSet(int flags) | ||
2357 | { | ||
2358 | |||
2359 | } | ||
2360 | |||
2361 | public override void VehicleFlagsRemove(int flags) | ||
2362 | { | ||
2363 | |||
2364 | } | ||
2355 | 2365 | ||
2356 | public override void SetVolumeDetect(int param) | 2366 | public override void SetVolumeDetect(int param) |
2357 | { | 2367 | { |
diff --git a/OpenSim/Region/Physics/POSPlugin/POSCharacter.cs b/OpenSim/Region/Physics/POSPlugin/POSCharacter.cs index 566b4e7..491e200 100644 --- a/OpenSim/Region/Physics/POSPlugin/POSCharacter.cs +++ b/OpenSim/Region/Physics/POSPlugin/POSCharacter.cs | |||
@@ -181,7 +181,17 @@ namespace OpenSim.Region.Physics.POSPlugin | |||
181 | { | 181 | { |
182 | 182 | ||
183 | } | 183 | } |
184 | |||
185 | public override void VehicleFlagsSet(int flags) | ||
186 | { | ||
187 | |||
188 | } | ||
189 | |||
190 | public override void VehicleFlagsRemove(int flags) | ||
191 | { | ||
184 | 192 | ||
193 | } | ||
194 | |||
185 | public override void SetVolumeDetect(int param) | 195 | public override void SetVolumeDetect(int param) |
186 | { | 196 | { |
187 | 197 | ||
diff --git a/OpenSim/Region/Physics/POSPlugin/POSPrim.cs b/OpenSim/Region/Physics/POSPlugin/POSPrim.cs index edccf47..f8d49f9 100644 --- a/OpenSim/Region/Physics/POSPlugin/POSPrim.cs +++ b/OpenSim/Region/Physics/POSPlugin/POSPrim.cs | |||
@@ -138,7 +138,17 @@ namespace OpenSim.Region.Physics.POSPlugin | |||
138 | { | 138 | { |
139 | 139 | ||
140 | } | 140 | } |
141 | |||
142 | public override void VehicleFlagsSet(int flags) | ||
143 | { | ||
141 | 144 | ||
145 | } | ||
146 | |||
147 | public override void VehicleFlagsRemove(int flags) | ||
148 | { | ||
149 | |||
150 | } | ||
151 | |||
142 | public override void SetVolumeDetect(int param) | 152 | public override void SetVolumeDetect(int param) |
143 | { | 153 | { |
144 | 154 | ||
diff --git a/OpenSim/Region/Physics/PhysXPlugin/PhysXPlugin.cs b/OpenSim/Region/Physics/PhysXPlugin/PhysXPlugin.cs index 24eb6b1..e54065c 100644 --- a/OpenSim/Region/Physics/PhysXPlugin/PhysXPlugin.cs +++ b/OpenSim/Region/Physics/PhysXPlugin/PhysXPlugin.cs | |||
@@ -370,7 +370,17 @@ namespace OpenSim.Region.Physics.PhysXPlugin | |||
370 | { | 370 | { |
371 | 371 | ||
372 | } | 372 | } |
373 | |||
374 | public override void VehicleFlagsSet(int flags) | ||
375 | { | ||
376 | |||
377 | } | ||
378 | |||
379 | public override void VehicleFlagsRemove(int flags) | ||
380 | { | ||
373 | 381 | ||
382 | } | ||
383 | |||
374 | public override void SetVolumeDetect(int param) | 384 | public override void SetVolumeDetect(int param) |
375 | { | 385 | { |
376 | 386 | ||
@@ -774,7 +784,17 @@ namespace OpenSim.Region.Physics.PhysXPlugin | |||
774 | { | 784 | { |
775 | 785 | ||
776 | } | 786 | } |
787 | |||
788 | public override void VehicleFlagsSet(int flags) | ||
789 | { | ||
790 | |||
791 | } | ||
792 | |||
793 | public override void VehicleFlagsRemove(int flags) | ||
794 | { | ||
777 | 795 | ||
796 | } | ||
797 | |||
778 | public override void SetVolumeDetect(int param) | 798 | public override void SetVolumeDetect(int param) |
779 | { | 799 | { |
780 | 800 | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 085d61f..33218aa 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | |||
@@ -6315,13 +6315,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6315 | public void llSetVehicleFlags(int flags) | 6315 | public void llSetVehicleFlags(int flags) |
6316 | { | 6316 | { |
6317 | m_host.AddScriptLPS(1); | 6317 | m_host.AddScriptLPS(1); |
6318 | NotImplemented("llSetVehicleFlags"); | 6318 | if (m_host.ParentGroup != null) |
6319 | { | ||
6320 | if (!m_host.ParentGroup.IsDeleted) | ||
6321 | { | ||
6322 | m_host.ParentGroup.RootPart.SetVehicleFlags(flags); | ||
6323 | } | ||
6324 | } | ||
6319 | } | 6325 | } |
6320 | 6326 | ||
6321 | public void llRemoveVehicleFlags(int flags) | 6327 | public void llRemoveVehicleFlags(int flags) |
6322 | { | 6328 | { |
6323 | m_host.AddScriptLPS(1); | 6329 | m_host.AddScriptLPS(1); |
6324 | NotImplemented("llRemoveVehicleFlags"); | 6330 | if (m_host.ParentGroup != null) |
6331 | { | ||
6332 | if (!m_host.ParentGroup.IsDeleted) | ||
6333 | { | ||
6334 | m_host.ParentGroup.RootPart.RemoveVehicleFlags(flags); | ||
6335 | } | ||
6336 | } | ||
6325 | } | 6337 | } |
6326 | 6338 | ||
6327 | public void llSitTarget(LSL_Vector offset, LSL_Rotation rot) | 6339 | public void llSitTarget(LSL_Vector offset, LSL_Rotation rot) |
@@ -8946,12 +8958,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8946 | LSLError("List must have at least 4 elements"); | 8958 | LSLError("List must have at least 4 elements"); |
8947 | return; | 8959 | return; |
8948 | } | 8960 | } |
8949 | m_host.ParentGroup.RootPart.PayPrice[0]=price; | 8961 | int[] nPrice = new int[5]; |
8950 | 8962 | nPrice[0]=price; | |
8951 | m_host.ParentGroup.RootPart.PayPrice[1]=(LSL_Integer)quick_pay_buttons.Data[0]; | 8963 | nPrice[1] = (LSL_Integer)quick_pay_buttons.Data[0]; |
8952 | m_host.ParentGroup.RootPart.PayPrice[2]=(LSL_Integer)quick_pay_buttons.Data[1]; | 8964 | nPrice[2] = (LSL_Integer)quick_pay_buttons.Data[1]; |
8953 | m_host.ParentGroup.RootPart.PayPrice[3]=(LSL_Integer)quick_pay_buttons.Data[2]; | 8965 | nPrice[3] = (LSL_Integer)quick_pay_buttons.Data[2]; |
8954 | m_host.ParentGroup.RootPart.PayPrice[4]=(LSL_Integer)quick_pay_buttons.Data[3]; | 8966 | nPrice[4] = (LSL_Integer)quick_pay_buttons.Data[3]; |
8967 | m_host.ParentGroup.RootPart.PayPrice = nPrice; | ||
8955 | m_host.ParentGroup.HasGroupChanged = true; | 8968 | m_host.ParentGroup.HasGroupChanged = true; |
8956 | } | 8969 | } |
8957 | 8970 | ||