mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-04-29 07:45:26 +00:00
integrated geometric representation with object definition, explosion target detection, and explosion resolution
This commit is contained in:
parent
9d86844396
commit
fe386bd79b
11 changed files with 531 additions and 138 deletions
|
|
@ -7,11 +7,12 @@ import net.psforever.objects.ce._
|
||||||
import net.psforever.objects.definition.{ComplexDeployableDefinition, SimpleDeployableDefinition}
|
import net.psforever.objects.definition.{ComplexDeployableDefinition, SimpleDeployableDefinition}
|
||||||
import net.psforever.objects.definition.converter.SmallDeployableConverter
|
import net.psforever.objects.definition.converter.SmallDeployableConverter
|
||||||
import net.psforever.objects.equipment.JammableUnit
|
import net.psforever.objects.equipment.JammableUnit
|
||||||
|
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||||
import net.psforever.objects.serverobject.damage.{Damageable, DamageableEntity}
|
import net.psforever.objects.serverobject.damage.{Damageable, DamageableEntity}
|
||||||
import net.psforever.objects.serverobject.damage.Damageable.Target
|
import net.psforever.objects.serverobject.damage.Damageable.Target
|
||||||
import net.psforever.objects.vital.resolution.ResolutionCalculations.Output
|
import net.psforever.objects.vital.resolution.ResolutionCalculations.Output
|
||||||
import net.psforever.objects.vital.SimpleResolutions
|
import net.psforever.objects.vital.{SimpleResolutions, Vitality}
|
||||||
import net.psforever.objects.vital.etc.TriggerUsedReason
|
import net.psforever.objects.vital.etc.TriggerUsedReason
|
||||||
import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult}
|
import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult}
|
||||||
import net.psforever.objects.vital.projectile.ProjectileReason
|
import net.psforever.objects.vital.projectile.ProjectileReason
|
||||||
|
|
@ -96,13 +97,33 @@ class ExplosiveDeployableControl(mine: ExplosiveDeployable) extends Actor with D
|
||||||
val originalHealth = mine.Health
|
val originalHealth = mine.Health
|
||||||
val cause = applyDamageTo(mine)
|
val cause = applyDamageTo(mine)
|
||||||
val damage = originalHealth - mine.Health
|
val damage = originalHealth - mine.Health
|
||||||
if (Damageable.CanDamageOrJammer(mine, damage, cause.interaction)) {
|
if (CanDetonate(mine, damage, cause.interaction)) {
|
||||||
ExplosiveDeployableControl.DamageResolution(mine, cause, damage)
|
ExplosiveDeployableControl.DamageResolution(mine, cause, damage)
|
||||||
} else {
|
} else {
|
||||||
mine.Health = originalHealth
|
mine.Health = originalHealth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A supplement for checking target susceptibility
|
||||||
|
* to account for sympathetic explosives even if there is no damage.
|
||||||
|
* This does not supercede other underlying checks or undo prior damage checks.
|
||||||
|
* @see `Damageable.CanDamageOrJammer`
|
||||||
|
* @see `DamageProperties.SympatheticExplosives`
|
||||||
|
* @param obj the entity being damaged
|
||||||
|
* @param damage the amount of damage
|
||||||
|
* @param data historical information about the damage
|
||||||
|
* @return `true`, if the target can be affected;
|
||||||
|
* `false`, otherwise
|
||||||
|
*/
|
||||||
|
def CanDetonate(obj: Vitality with FactionAffinity, damage: Int, data: DamageInteraction): Boolean = {
|
||||||
|
if (damage == 0 && data.cause.source.SympatheticExplosion) {
|
||||||
|
Damageable.CanDamageOrJammer(mine, damage = 1, data)
|
||||||
|
} else {
|
||||||
|
Damageable.CanDamageOrJammer(mine, damage, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object ExplosiveDeployableControl {
|
object ExplosiveDeployableControl {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import net.psforever.objects.serverobject.turret.{FacilityTurretDefinition, Turr
|
||||||
import net.psforever.objects.vehicles.{DestroyedVehicle, InternalTelepadDefinition, SeatArmorRestriction, UtilityType}
|
import net.psforever.objects.vehicles.{DestroyedVehicle, InternalTelepadDefinition, SeatArmorRestriction, UtilityType}
|
||||||
import net.psforever.objects.vital.base.DamageType
|
import net.psforever.objects.vital.base.DamageType
|
||||||
import net.psforever.objects.vital.damage._
|
import net.psforever.objects.vital.damage._
|
||||||
|
import net.psforever.objects.vital.etc.ExplodingRadialDegrade
|
||||||
import net.psforever.objects.vital.projectile._
|
import net.psforever.objects.vital.projectile._
|
||||||
import net.psforever.objects.vital.prop.DamageWithPosition
|
import net.psforever.objects.vital.prop.DamageWithPosition
|
||||||
import net.psforever.objects.vital.{ComplexDeployableResolutions, MaxResolutions, SimpleResolutions}
|
import net.psforever.objects.vital.{ComplexDeployableResolutions, MaxResolutions, SimpleResolutions}
|
||||||
|
|
@ -5626,7 +5627,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 225
|
Damage1 = 225
|
||||||
DamageRadius = 5
|
DamageRadius = 5
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
fury.DrownAtMaxDepth = true
|
fury.DrownAtMaxDepth = true
|
||||||
fury.MaxDepth = 1.3f
|
fury.MaxDepth = 1.3f
|
||||||
|
|
@ -5657,7 +5658,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 225
|
Damage1 = 225
|
||||||
DamageRadius = 5
|
DamageRadius = 5
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
quadassault.DrownAtMaxDepth = true
|
quadassault.DrownAtMaxDepth = true
|
||||||
quadassault.MaxDepth = 1.3f
|
quadassault.MaxDepth = 1.3f
|
||||||
|
|
@ -5688,7 +5689,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 225
|
Damage1 = 225
|
||||||
DamageRadius = 5
|
DamageRadius = 5
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
quadstealth.DrownAtMaxDepth = true
|
quadstealth.DrownAtMaxDepth = true
|
||||||
quadstealth.MaxDepth = 1.25f
|
quadstealth.MaxDepth = 1.25f
|
||||||
|
|
@ -5721,7 +5722,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 8
|
DamageRadius = 8
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
two_man_assault_buggy.DrownAtMaxDepth = true
|
two_man_assault_buggy.DrownAtMaxDepth = true
|
||||||
two_man_assault_buggy.MaxDepth = 1.5f
|
two_man_assault_buggy.MaxDepth = 1.5f
|
||||||
|
|
@ -5756,7 +5757,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 8
|
DamageRadius = 8
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
skyguard.DrownAtMaxDepth = true
|
skyguard.DrownAtMaxDepth = true
|
||||||
skyguard.MaxDepth = 1.5f
|
skyguard.MaxDepth = 1.5f
|
||||||
|
|
@ -5795,7 +5796,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 10
|
DamageRadius = 10
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
threemanheavybuggy.DrownAtMaxDepth = true
|
threemanheavybuggy.DrownAtMaxDepth = true
|
||||||
threemanheavybuggy.MaxDepth = 1.83f
|
threemanheavybuggy.MaxDepth = 1.83f
|
||||||
|
|
@ -5829,7 +5830,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 8
|
DamageRadius = 8
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
twomanheavybuggy.DrownAtMaxDepth = true
|
twomanheavybuggy.DrownAtMaxDepth = true
|
||||||
twomanheavybuggy.MaxDepth = 1.95f
|
twomanheavybuggy.MaxDepth = 1.95f
|
||||||
|
|
@ -5863,7 +5864,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 10
|
DamageRadius = 10
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
twomanhoverbuggy.DrownAtMaxDepth = true
|
twomanhoverbuggy.DrownAtMaxDepth = true
|
||||||
twomanhoverbuggy.UnderwaterLifespan(suffocation = 45000L, recovery = 5000L) //but the thresher hovers over water, so ...?
|
twomanhoverbuggy.UnderwaterLifespan(suffocation = 45000L, recovery = 5000L) //but the thresher hovers over water, so ...?
|
||||||
|
|
@ -5903,7 +5904,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 12
|
DamageRadius = 12
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
mediumtransport.DrownAtMaxDepth = false
|
mediumtransport.DrownAtMaxDepth = false
|
||||||
mediumtransport.MaxDepth = 1.2f
|
mediumtransport.MaxDepth = 1.2f
|
||||||
|
|
@ -5947,7 +5948,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 12
|
DamageRadius = 12
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
battlewagon.DrownAtMaxDepth = true
|
battlewagon.DrownAtMaxDepth = true
|
||||||
battlewagon.MaxDepth = 1.2f
|
battlewagon.MaxDepth = 1.2f
|
||||||
|
|
@ -5988,7 +5989,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 12
|
DamageRadius = 12
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
thunderer.DrownAtMaxDepth = true
|
thunderer.DrownAtMaxDepth = true
|
||||||
thunderer.MaxDepth = 1.2f
|
thunderer.MaxDepth = 1.2f
|
||||||
|
|
@ -6029,7 +6030,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 12
|
DamageRadius = 12
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
aurora.DrownAtMaxDepth = true
|
aurora.DrownAtMaxDepth = true
|
||||||
aurora.MaxDepth = 1.2f
|
aurora.MaxDepth = 1.2f
|
||||||
|
|
@ -6093,7 +6094,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 450
|
Damage1 = 450
|
||||||
DamageRadius = 15
|
DamageRadius = 15
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
apc_tr.DrownAtMaxDepth = true
|
apc_tr.DrownAtMaxDepth = true
|
||||||
apc_tr.MaxDepth = 3
|
apc_tr.MaxDepth = 3
|
||||||
|
|
@ -6157,7 +6158,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 450
|
Damage1 = 450
|
||||||
DamageRadius = 15
|
DamageRadius = 15
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
apc_nc.DrownAtMaxDepth = true
|
apc_nc.DrownAtMaxDepth = true
|
||||||
apc_nc.MaxDepth = 3
|
apc_nc.MaxDepth = 3
|
||||||
|
|
@ -6221,7 +6222,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 450
|
Damage1 = 450
|
||||||
DamageRadius = 15
|
DamageRadius = 15
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
apc_vs.DrownAtMaxDepth = true
|
apc_vs.DrownAtMaxDepth = true
|
||||||
apc_vs.MaxDepth = 3
|
apc_vs.MaxDepth = 3
|
||||||
|
|
@ -6253,7 +6254,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 375
|
Damage1 = 375
|
||||||
DamageRadius = 10
|
DamageRadius = 10
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
lightning.DrownAtMaxDepth = true
|
lightning.DrownAtMaxDepth = true
|
||||||
lightning.MaxDepth = 1.38f
|
lightning.MaxDepth = 1.38f
|
||||||
|
|
@ -6290,7 +6291,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 375
|
Damage1 = 375
|
||||||
DamageRadius = 12
|
DamageRadius = 12
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
prowler.DrownAtMaxDepth = true
|
prowler.DrownAtMaxDepth = true
|
||||||
prowler.MaxDepth = 3
|
prowler.MaxDepth = 3
|
||||||
|
|
@ -6323,7 +6324,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 375
|
Damage1 = 375
|
||||||
DamageRadius = 12
|
DamageRadius = 12
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
vanguard.DrownAtMaxDepth = true
|
vanguard.DrownAtMaxDepth = true
|
||||||
vanguard.MaxDepth = 2.7f
|
vanguard.MaxDepth = 2.7f
|
||||||
|
|
@ -6358,7 +6359,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 375
|
Damage1 = 375
|
||||||
DamageRadius = 12
|
DamageRadius = 12
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
magrider.DrownAtMaxDepth = true
|
magrider.DrownAtMaxDepth = true
|
||||||
magrider.MaxDepth = 2
|
magrider.MaxDepth = 2
|
||||||
|
|
@ -6391,7 +6392,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 450
|
Damage1 = 450
|
||||||
DamageRadius = 12
|
DamageRadius = 12
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
ant.DrownAtMaxDepth = true
|
ant.DrownAtMaxDepth = true
|
||||||
ant.MaxDepth = 2
|
ant.MaxDepth = 2
|
||||||
|
|
@ -6427,7 +6428,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 450
|
Damage1 = 450
|
||||||
DamageRadius = 15
|
DamageRadius = 15
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
ams.DrownAtMaxDepth = true
|
ams.DrownAtMaxDepth = true
|
||||||
ams.MaxDepth = 3
|
ams.MaxDepth = 3
|
||||||
|
|
@ -6463,7 +6464,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 10
|
DamageRadius = 10
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
router.DrownAtMaxDepth = true
|
router.DrownAtMaxDepth = true
|
||||||
router.MaxDepth = 2
|
router.MaxDepth = 2
|
||||||
|
|
@ -6499,7 +6500,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 10
|
DamageRadius = 10
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
switchblade.DrownAtMaxDepth = true
|
switchblade.DrownAtMaxDepth = true
|
||||||
switchblade.MaxDepth = 2
|
switchblade.MaxDepth = 2
|
||||||
|
|
@ -6533,7 +6534,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 10
|
DamageRadius = 10
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
flail.DrownAtMaxDepth = true
|
flail.DrownAtMaxDepth = true
|
||||||
flail.MaxDepth = 2
|
flail.MaxDepth = 2
|
||||||
|
|
@ -6567,7 +6568,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 10
|
DamageRadius = 10
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
mosquito.DrownAtMaxDepth = true
|
mosquito.DrownAtMaxDepth = true
|
||||||
mosquito.MaxDepth = 2 //flying vehicles will automatically disable
|
mosquito.MaxDepth = 2 //flying vehicles will automatically disable
|
||||||
|
|
@ -6601,7 +6602,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 375
|
Damage1 = 375
|
||||||
DamageRadius = 12
|
DamageRadius = 12
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
lightgunship.DrownAtMaxDepth = true
|
lightgunship.DrownAtMaxDepth = true
|
||||||
lightgunship.MaxDepth = 2 //flying vehicles will automatically disable
|
lightgunship.MaxDepth = 2 //flying vehicles will automatically disable
|
||||||
|
|
@ -6634,7 +6635,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 10
|
DamageRadius = 10
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
wasp.DrownAtMaxDepth = true
|
wasp.DrownAtMaxDepth = true
|
||||||
wasp.MaxDepth = 2 //flying vehicles will automatically disable
|
wasp.MaxDepth = 2 //flying vehicles will automatically disable
|
||||||
|
|
@ -6675,7 +6676,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 375
|
Damage1 = 375
|
||||||
DamageRadius = 12
|
DamageRadius = 12
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
liberator.DrownAtMaxDepth = true
|
liberator.DrownAtMaxDepth = true
|
||||||
liberator.MaxDepth = 2 //flying vehicles will automatically disable
|
liberator.MaxDepth = 2 //flying vehicles will automatically disable
|
||||||
|
|
@ -6717,7 +6718,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 375
|
Damage1 = 375
|
||||||
DamageRadius = 12
|
DamageRadius = 12
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
vulture.DrownAtMaxDepth = true
|
vulture.DrownAtMaxDepth = true
|
||||||
vulture.MaxDepth = 2 //flying vehicles will automatically disable
|
vulture.MaxDepth = 2 //flying vehicles will automatically disable
|
||||||
|
|
@ -6791,7 +6792,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 450
|
Damage1 = 450
|
||||||
DamageRadius = 30
|
DamageRadius = 30
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
dropship.DrownAtMaxDepth = true
|
dropship.DrownAtMaxDepth = true
|
||||||
dropship.MaxDepth = 2
|
dropship.MaxDepth = 2
|
||||||
|
|
@ -6844,7 +6845,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 450
|
Damage1 = 450
|
||||||
DamageRadius = 30
|
DamageRadius = 30
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
galaxy_gunship.DrownAtMaxDepth = true
|
galaxy_gunship.DrownAtMaxDepth = true
|
||||||
galaxy_gunship.MaxDepth = 2
|
galaxy_gunship.MaxDepth = 2
|
||||||
|
|
@ -6885,7 +6886,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 450
|
Damage1 = 450
|
||||||
DamageRadius = 30
|
DamageRadius = 30
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
lodestar.DrownAtMaxDepth = true
|
lodestar.DrownAtMaxDepth = true
|
||||||
lodestar.MaxDepth = 2
|
lodestar.MaxDepth = 2
|
||||||
|
|
@ -6927,7 +6928,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 150
|
Damage1 = 150
|
||||||
DamageRadius = 12
|
DamageRadius = 12
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
phantasm.DrownAtMaxDepth = true
|
phantasm.DrownAtMaxDepth = true
|
||||||
phantasm.MaxDepth = 2
|
phantasm.MaxDepth = 2
|
||||||
|
|
@ -6969,7 +6970,7 @@ object GlobalDefinitions {
|
||||||
Damage4 = 1850
|
Damage4 = 1850
|
||||||
DamageRadius = 5.1f
|
DamageRadius = 5.1f
|
||||||
DamageAtEdge = 0.1f
|
DamageAtEdge = 0.1f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
|
|
||||||
he_mine.Name = "he_mine"
|
he_mine.Name = "he_mine"
|
||||||
|
|
@ -6990,7 +6991,7 @@ object GlobalDefinitions {
|
||||||
Damage4 = 1600
|
Damage4 = 1600
|
||||||
DamageRadius = 6.6f
|
DamageRadius = 6.6f
|
||||||
DamageAtEdge = 0.25f
|
DamageAtEdge = 0.25f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
|
|
||||||
jammer_mine.Name = "jammer_mine"
|
jammer_mine.Name = "jammer_mine"
|
||||||
|
|
@ -7022,7 +7023,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 8
|
DamageRadius = 8
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
|
|
||||||
spitfire_cloaked.Name = "spitfire_cloaked"
|
spitfire_cloaked.Name = "spitfire_cloaked"
|
||||||
|
|
@ -7044,7 +7045,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 75
|
Damage1 = 75
|
||||||
DamageRadius = 8
|
DamageRadius = 8
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
|
|
||||||
spitfire_aa.Name = "spitfire_aa"
|
spitfire_aa.Name = "spitfire_aa"
|
||||||
|
|
@ -7066,7 +7067,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 8
|
DamageRadius = 8
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
|
|
||||||
motionalarmsensor.Name = "motionalarmsensor"
|
motionalarmsensor.Name = "motionalarmsensor"
|
||||||
|
|
@ -7100,7 +7101,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 10
|
Damage1 = 10
|
||||||
DamageRadius = 8
|
DamageRadius = 8
|
||||||
DamageAtEdge = 0.2f
|
DamageAtEdge = 0.2f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
|
|
||||||
val fieldTurretConverter = new FieldTurretConverter
|
val fieldTurretConverter = new FieldTurretConverter
|
||||||
|
|
@ -7127,7 +7128,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 8
|
DamageRadius = 8
|
||||||
DamageAtEdge = 0.1f
|
DamageAtEdge = 0.1f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
|
|
||||||
portable_manned_turret_nc.Name = "portable_manned_turret_nc"
|
portable_manned_turret_nc.Name = "portable_manned_turret_nc"
|
||||||
|
|
@ -7153,7 +7154,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 8
|
DamageRadius = 8
|
||||||
DamageAtEdge = 0.1f
|
DamageAtEdge = 0.1f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
|
|
||||||
portable_manned_turret_tr.Name = "portable_manned_turret_tr"
|
portable_manned_turret_tr.Name = "portable_manned_turret_tr"
|
||||||
|
|
@ -7179,7 +7180,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 8
|
DamageRadius = 8
|
||||||
DamageAtEdge = 0.1f
|
DamageAtEdge = 0.1f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
|
|
||||||
portable_manned_turret_vs.Name = "portable_manned_turret_vs"
|
portable_manned_turret_vs.Name = "portable_manned_turret_vs"
|
||||||
|
|
@ -7205,7 +7206,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 8
|
DamageRadius = 8
|
||||||
DamageAtEdge = 0.1f
|
DamageAtEdge = 0.1f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
|
|
||||||
deployable_shield_generator.Name = "deployable_shield_generator"
|
deployable_shield_generator.Name = "deployable_shield_generator"
|
||||||
|
|
@ -7668,7 +7669,7 @@ object GlobalDefinitions {
|
||||||
Damage1 = 300
|
Damage1 = 300
|
||||||
DamageRadius = 5
|
DamageRadius = 5
|
||||||
DamageAtEdge = 0.1f
|
DamageAtEdge = 0.1f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
}
|
}
|
||||||
|
|
||||||
vanu_sentry_turret.Name = "vanu_sentry_turret"
|
vanu_sentry_turret.Name = "vanu_sentry_turret"
|
||||||
|
|
@ -7770,7 +7771,7 @@ object GlobalDefinitions {
|
||||||
DamageRadius = 15.75f
|
DamageRadius = 15.75f
|
||||||
DamageRadiusMin = 14
|
DamageRadiusMin = 14
|
||||||
DamageAtEdge = 0.00002f
|
DamageAtEdge = 0.00002f
|
||||||
Modifiers = RadialDegrade
|
Modifiers = ExplodingRadialDegrade
|
||||||
//damage is 99999 at 14m, dropping rapidly to ~1 at 15.75m
|
//damage is 99999 at 14m, dropping rapidly to ~1 at 15.75m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ final case class PlayerSource(
|
||||||
position: Vector3,
|
position: Vector3,
|
||||||
orientation: Vector3,
|
orientation: Vector3,
|
||||||
velocity: Option[Vector3],
|
velocity: Option[Vector3],
|
||||||
|
crouching: Boolean,
|
||||||
|
jumping: Boolean,
|
||||||
modifiers: ResistanceProfile
|
modifiers: ResistanceProfile
|
||||||
) extends SourceEntry {
|
) extends SourceEntry {
|
||||||
override def Name = name
|
override def Name = name
|
||||||
|
|
@ -48,6 +50,8 @@ object PlayerSource {
|
||||||
tplayer.Position,
|
tplayer.Position,
|
||||||
tplayer.Orientation,
|
tplayer.Orientation,
|
||||||
tplayer.Velocity,
|
tplayer.Velocity,
|
||||||
|
tplayer.Crouching,
|
||||||
|
tplayer.Jumping,
|
||||||
ExoSuitDefinition.Select(tplayer.ExoSuit, tplayer.Faction)
|
ExoSuitDefinition.Select(tplayer.ExoSuit, tplayer.Faction)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,17 @@ package net.psforever.objects.definition
|
||||||
|
|
||||||
import net.psforever.objects.avatar.Avatars
|
import net.psforever.objects.avatar.Avatars
|
||||||
import net.psforever.objects.definition.converter.AvatarConverter
|
import net.psforever.objects.definition.converter.AvatarConverter
|
||||||
|
import net.psforever.objects.geometry.GeometryForm
|
||||||
import net.psforever.objects.vital.VitalityDefinition
|
import net.psforever.objects.vital.VitalityDefinition
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The definition for game objects that look like other people, and also for players.
|
* The definition for game objects that look like players.
|
||||||
* @param objectId the object's identifier number
|
* @param objectId the object type number
|
||||||
*/
|
*/
|
||||||
class AvatarDefinition(objectId: Int) extends ObjectDefinition(objectId) with VitalityDefinition {
|
class AvatarDefinition(objectId: Int) extends ObjectDefinition(objectId) with VitalityDefinition {
|
||||||
Avatars(objectId) //let throw NoSuchElementException
|
Avatars(objectId) //let throw NoSuchElementException
|
||||||
Packet = AvatarDefinition.converter
|
Packet = AvatarDefinition.converter
|
||||||
|
Geometry = GeometryForm.representPlayerByCylinder(radius = 1.6f)
|
||||||
}
|
}
|
||||||
|
|
||||||
object AvatarDefinition {
|
object AvatarDefinition {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package net.psforever.objects.definition
|
||||||
|
|
||||||
import net.psforever.objects.PlanetSideGameObject
|
import net.psforever.objects.PlanetSideGameObject
|
||||||
import net.psforever.objects.definition.converter.{ObjectCreateConverter, PacketConverter}
|
import net.psforever.objects.definition.converter.{ObjectCreateConverter, PacketConverter}
|
||||||
|
import net.psforever.objects.geometry.{Geometry3D, GeometryForm}
|
||||||
import net.psforever.types.OxygenState
|
import net.psforever.types.OxygenState
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -76,5 +77,27 @@ abstract class ObjectDefinition(private val objectId: Int) extends BasicDefiniti
|
||||||
UnderwaterLifespan()
|
UnderwaterLifespan()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var serverSplashTargetsCentroid: Boolean = false
|
||||||
|
|
||||||
|
def ServerSplashTargetsCentroid: Boolean = serverSplashTargetsCentroid
|
||||||
|
|
||||||
|
def ServerSplashTargetsCentroid_=(splash: Boolean): Boolean = {
|
||||||
|
serverSplashTargetsCentroid = splash
|
||||||
|
ServerSplashTargetsCentroid
|
||||||
|
}
|
||||||
|
|
||||||
|
private var serverGeometry: Any => Geometry3D = GeometryForm.representByPoint()
|
||||||
|
|
||||||
|
def Geometry: Any => Geometry3D = if (ServerSplashTargetsCentroid) {
|
||||||
|
serverGeometry
|
||||||
|
} else {
|
||||||
|
GeometryForm.representByPoint()
|
||||||
|
}
|
||||||
|
|
||||||
|
def Geometry_=(func: Any => Geometry3D): Any => Geometry3D = {
|
||||||
|
serverGeometry = func
|
||||||
|
Geometry
|
||||||
|
}
|
||||||
|
|
||||||
def ObjectId: Int = objectId
|
def ObjectId: Int = objectId
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ import net.psforever.types.Vector3
|
||||||
object Closest {
|
object Closest {
|
||||||
object Distance {
|
object Distance {
|
||||||
def apply(point : Vector3, seg : Segment2D) : Float = {
|
def apply(point : Vector3, seg : Segment2D) : Float = {
|
||||||
val segdx = seg.bx - seg.ax
|
val segdx = seg.p2.x - seg.p1.x
|
||||||
val segdy = seg.by - seg.ay
|
val segdy = seg.p2.y - seg.p1.y
|
||||||
((point.x - seg.ax) * segdx + (point.y - seg.ay) * segdy) /
|
((point.x - seg.p1.x) * segdx + (point.y - seg.p1.y) * segdy) /
|
||||||
Vector3.MagnitudeSquared(Vector3(segdx, segdy, 0))
|
Vector3.MagnitudeSquared(Vector3(segdx, segdy, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -18,7 +18,7 @@ object Closest {
|
||||||
} else {
|
} else {
|
||||||
math.abs(
|
math.abs(
|
||||||
Vector3.DotProduct(
|
Vector3.DotProduct(
|
||||||
Vector3(line2.x - line1.x, line2.y - line1.y, 0),
|
Vector3(line2.p.x - line1.p.x, line2.p.y - line1.p.y, 0),
|
||||||
Vector3(-1/line1.d.y, 1/line1.d.x, 0)
|
Vector3(-1/line1.d.y, 1/line1.d.x, 0)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -29,10 +29,10 @@ object Closest {
|
||||||
if (Intersection.Test(seg1, seg2)) { //intersecting line segments
|
if (Intersection.Test(seg1, seg2)) { //intersecting line segments
|
||||||
0f
|
0f
|
||||||
} else {
|
} else {
|
||||||
val v1a = Vector3(seg1.ax, seg1.ay, 0)
|
val v1a = Vector3(seg1.p1.x, seg1.p1.y, 0)
|
||||||
val v2a = Vector3(seg2.ax, seg2.ay, 0)
|
val v2a = Vector3(seg2.p1.x, seg2.p1.y, 0)
|
||||||
val v1b = Vector3(seg1.bx, seg1.by, 0)
|
val v1b = Vector3(seg1.p2.x, seg1.p2.y, 0)
|
||||||
val v2b = Vector3(seg2.bx, seg2.by, 0)
|
val v2b = Vector3(seg2.p2.x, seg2.p2.y, 0)
|
||||||
math.min(
|
math.min(
|
||||||
apply(v1a, seg2),
|
apply(v1a, seg2),
|
||||||
math.min(
|
math.min(
|
||||||
|
|
@ -47,7 +47,7 @@ object Closest {
|
||||||
}
|
}
|
||||||
|
|
||||||
def apply(c1: Circle, c2 : Circle): Float = {
|
def apply(c1: Circle, c2 : Circle): Float = {
|
||||||
math.max(0, Vector3.Magnitude(Vector3(c1.x - c2.x, c1.y - c2.y, 0)) - c1.radius - c2.radius)
|
math.max(0, Vector3.Magnitude(Vector3(c1.p.x - c2.p.x, c1.p.y - c2.p.y, 0)) - c1.radius - c2.radius)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -62,12 +62,12 @@ object Closest {
|
||||||
val cross = Vector3.CrossProduct(line1.d, line2.d)
|
val cross = Vector3.CrossProduct(line1.d, line2.d)
|
||||||
if(cross != Vector3.Zero) {
|
if(cross != Vector3.Zero) {
|
||||||
math.abs(
|
math.abs(
|
||||||
Vector3.DotProduct(cross, Vector3(line1.x - line2.x, line1.y - line2.y, line1.z - line2.z))
|
Vector3.DotProduct(cross, Vector3(line1.p.x - line2.p.x, line1.p.y - line2.p.y, line1.p.z - line2.p.z))
|
||||||
) / Vector3.Magnitude(cross)
|
) / Vector3.Magnitude(cross)
|
||||||
} else {
|
} else {
|
||||||
// lines are parallel or coincidental
|
// lines are parallel or coincidental
|
||||||
// construct a right triangle with one leg on line1 and the hypotenuse between the line's known points
|
// construct a right triangle with one leg on line1 and the hypotenuse between the line's known points
|
||||||
val hypotenuse = Vector3(line2.x - line1.x, line2.y - line1.y, line2.z - line1.z)
|
val hypotenuse = Vector3(line2.p.x - line1.p.x, line2.p.y - line1.p.y, line2.p.z - line1.p.z)
|
||||||
val legOnLine1 = line1.d * Vector3.DotProduct(hypotenuse, line1.d)
|
val legOnLine1 = line1.d * Vector3.DotProduct(hypotenuse, line1.d)
|
||||||
Vector3.Magnitude(hypotenuse - legOnLine1)
|
Vector3.Magnitude(hypotenuse - legOnLine1)
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +82,7 @@ object Closest {
|
||||||
}
|
}
|
||||||
|
|
||||||
def apply(s1: Sphere, s2 : Sphere): Float = {
|
def apply(s1: Sphere, s2 : Sphere): Float = {
|
||||||
math.max(0, Vector3.Magnitude(Vector3(s1.x - s2.x, s1.y - s2.y, s1.z - s2.z)) - s1.radius - s2.radius)
|
math.max(0, Vector3.Magnitude(Vector3(s1.p.x - s2.p.x, s1.p.y - s2.p.y, s1.p.z - s2.p.z)) - s1.radius - s2.radius)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,9 +97,9 @@ object Closest {
|
||||||
def apply(c1 : Circle, c2 : Circle): Option[Segment2D] = {
|
def apply(c1 : Circle, c2 : Circle): Option[Segment2D] = {
|
||||||
val distance = Distance(c1, c2)
|
val distance = Distance(c1, c2)
|
||||||
if (distance > 0) {
|
if (distance > 0) {
|
||||||
val c1x = c1.x
|
val c1x = c1.p.x
|
||||||
val c1y = c1.y
|
val c1y = c1.p.y
|
||||||
val v = Vector3.Unit(Vector3(c2.x - c1x, c2.y - c1y, 0f))
|
val v = Vector3.Unit(Vector3(c2.p.x - c1x, c2.p.y - c1y, 0f))
|
||||||
val c1d = v * c1.radius
|
val c1d = v * c1.radius
|
||||||
val c2d = v * c2.radius
|
val c2d = v * c2.radius
|
||||||
Some(
|
Some(
|
||||||
|
|
@ -122,8 +122,8 @@ object Closest {
|
||||||
* `None`, if the lines intersect with each other
|
* `None`, if the lines intersect with each other
|
||||||
*/
|
*/
|
||||||
def apply(line1 : Line3D, line2 : Line3D): Option[Segment3D] = {
|
def apply(line1 : Line3D, line2 : Line3D): Option[Segment3D] = {
|
||||||
val p1 = Vector3(line1.x, line1.y, line1.z)
|
val p1 = Vector3(line1.p.x, line1.p.y, line1.p.z)
|
||||||
val p3 = Vector3(line2.x, line2.y, line2.z)
|
val p3 = Vector3(line2.p.x, line2.p.y, line2.p.z)
|
||||||
val p13 = p1 - p3 // vector between point on first line and point on second line
|
val p13 = p1 - p3 // vector between point on first line and point on second line
|
||||||
val p43 = line2.d
|
val p43 = line2.d
|
||||||
val p21 = line1.d
|
val p21 = line1.d
|
||||||
|
|
@ -141,12 +141,12 @@ object Closest {
|
||||||
if (p21 == p13u || p21 == Vector3.neg(p13u)) { //coincidental lines overlap / intersect
|
if (p21 == p13u || p21 == Vector3.neg(p13u)) { //coincidental lines overlap / intersect
|
||||||
None
|
None
|
||||||
} else { //parallel lines
|
} else { //parallel lines
|
||||||
val connecting = Vector3(line2.x - line1.x, line2.y - line1.y, line2.z - line1.z)
|
val connecting = Vector3(line2.p.x - line1.p.x, line2.p.y - line1.p.y, line2.p.z - line1.p.z)
|
||||||
val legOnLine1 = line1.d * Vector3.DotProduct(connecting, line1.d)
|
val legOnLine1 = line1.d * Vector3.DotProduct(connecting, line1.d)
|
||||||
val v = connecting - legOnLine1
|
val v = connecting - legOnLine1
|
||||||
Some(Segment3D(
|
Some(Segment3D(
|
||||||
line1.x, line1.y, line1.z,
|
line1.p.x, line1.p.y, line1.p.z,
|
||||||
line1.x + v.x, line1.y + v.y, line1.z + v.z
|
line1.p.x + v.x, line1.p.y + v.y, line1.p.z + v.z
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -169,25 +169,25 @@ object Closest {
|
||||||
def apply(line1 : Segment3D, line2 : Segment3D): Option[Segment3D] = {
|
def apply(line1 : Segment3D, line2 : Segment3D): Option[Segment3D] = {
|
||||||
val uline1 = Vector3.Unit(line1.d)
|
val uline1 = Vector3.Unit(line1.d)
|
||||||
val uline2 = Vector3.Unit(line2.d)
|
val uline2 = Vector3.Unit(line2.d)
|
||||||
apply(Line3D(line1.ax, line1.ay, line1.az, uline1), Line3D(line2.ax, line2.ay, line2.az, uline2)) match {
|
apply(Line3D(line1.p1.x, line1.p1.y, line1.p1.z, uline1), Line3D(line2.p1.x, line2.p1.y, line2.p1.z, uline2)) match {
|
||||||
case Some(seg: Segment3D) => // common skew lines and parallel lines
|
case Some(seg: Segment3D) => // common skew lines and parallel lines
|
||||||
val sega = Vector3(seg.ax, seg.ay, seg.az)
|
val sega = Vector3(seg.p1.x, seg.p1.y, seg.p1.z)
|
||||||
val p1 = Vector3(line1.ax, line1.ay, line1.az)
|
val p1 = Vector3(line1.p1.x, line1.p1.y, line1.p1.z)
|
||||||
val d1 = sega - p1
|
val d1 = sega - p1
|
||||||
val out1 = if (!Geometry.equalVectors(Vector3.Unit(d1), uline1)) { //clamp seg.a(xyz) to segment line1's bounds
|
val out1 = if (!Geometry.equalVectors(Vector3.Unit(d1), uline1)) { //clamp seg.a(xyz) to segment line1's bounds
|
||||||
p1
|
p1
|
||||||
} else if (Vector3.MagnitudeSquared(d1) > Vector3.MagnitudeSquared(line1.d)) {
|
} else if (Vector3.MagnitudeSquared(d1) > Vector3.MagnitudeSquared(line1.d)) {
|
||||||
Vector3(line1.bx, line1.by, line1.bz)
|
Vector3(line1.p2.x, line1.p2.y, line1.p2.z)
|
||||||
} else {
|
} else {
|
||||||
sega
|
sega
|
||||||
}
|
}
|
||||||
val segb = Vector3(seg.bx, seg.by, seg.bz)
|
val segb = Vector3(seg.p2.x, seg.p2.y, seg.p2.z)
|
||||||
val p2 = Vector3(line2.ax, line2.ay, line2.az)
|
val p2 = Vector3(line2.p1.x, line2.p1.y, line2.p1.z)
|
||||||
val d2 = segb - p2
|
val d2 = segb - p2
|
||||||
val out2 = if (!Geometry.equalVectors(Vector3.Unit(d2), uline2)) { //clamp seg.b(xyz) to segment line2's bounds
|
val out2 = if (!Geometry.equalVectors(Vector3.Unit(d2), uline2)) { //clamp seg.b(xyz) to segment line2's bounds
|
||||||
p2
|
p2
|
||||||
} else if (Vector3.MagnitudeSquared(d2) > Vector3.MagnitudeSquared(line2.d)) {
|
} else if (Vector3.MagnitudeSquared(d2) > Vector3.MagnitudeSquared(line2.d)) {
|
||||||
Vector3(line2.bx, line2.by, line2.bz)
|
Vector3(line2.p2.x, line2.p2.y, line2.p2.z)
|
||||||
} else {
|
} else {
|
||||||
segb
|
segb
|
||||||
}
|
}
|
||||||
|
|
@ -196,19 +196,19 @@ object Closest {
|
||||||
out2.x, out2.y, out2.z
|
out2.x, out2.y, out2.z
|
||||||
))
|
))
|
||||||
case None =>
|
case None =>
|
||||||
val connectingU = Vector3.Unit(Vector3(line2.ax - line1.ax, line2.ay - line1.ay, line2.az - line1.az))
|
val connectingU = Vector3.Unit(Vector3(line2.p1.x - line1.p1.x, line2.p1.y - line1.p1.y, line2.p1.z - line1.p1.z))
|
||||||
if (uline1 == connectingU || uline1 == Vector3.neg(connectingU)) { // coincidental line segments
|
if (uline1 == connectingU || uline1 == Vector3.neg(connectingU)) { // coincidental line segments
|
||||||
val line1a = Vector3(line1.ax, line1.ay, line1.az)
|
val line1a = Vector3(line1.p1.x, line1.p1.y, line1.p1.z)
|
||||||
val line1b = Vector3(line1.bx, line1.by, line1.bz)
|
val line1b = Vector3(line1.p2.x, line1.p2.y, line1.p2.z)
|
||||||
val line2a = Vector3(line2.ax, line2.ay, line2.az)
|
val line2a = Vector3(line2.p1.x, line2.p1.y, line2.p1.z)
|
||||||
val line2b = Vector3(line2.bx, line2.by, line2.bz)
|
val line2b = Vector3(line2.p2.x, line2.p2.y, line2.p2.z)
|
||||||
if (Vector3.Unit(line2a - line1a) != Vector3.Unit(line2b - line1a) ||
|
if (Vector3.Unit(line2a - line1a) != Vector3.Unit(line2b - line1a) ||
|
||||||
Vector3.Unit(line2a - line1b) != Vector3.Unit(line2b - line1b) ||
|
Vector3.Unit(line2a - line1b) != Vector3.Unit(line2b - line1b) ||
|
||||||
Vector3.Unit(line1a - line2a) != Vector3.Unit(line1b - line2a) ||
|
Vector3.Unit(line1a - line2a) != Vector3.Unit(line1b - line2a) ||
|
||||||
Vector3.Unit(line1a - line2b) != Vector3.Unit(line1b - line2b)) {
|
Vector3.Unit(line1a - line2b) != Vector3.Unit(line1b - line2b)) {
|
||||||
Some(Segment3D(
|
Some(Segment3D(
|
||||||
line1.ax, line1.ay, line1a.z,
|
line1.p1.x, line1.p1.y, line1a.z,
|
||||||
line1.ax, line1.ay, line1a.z
|
line1.p1.x, line1.p1.y, line1a.z
|
||||||
)) // overlap regions
|
)) // overlap regions
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -245,10 +245,10 @@ object Closest {
|
||||||
def apply(s1 : Sphere, s2 : Sphere): Option[Segment3D] = {
|
def apply(s1 : Sphere, s2 : Sphere): Option[Segment3D] = {
|
||||||
val distance = Distance(s1, s2)
|
val distance = Distance(s1, s2)
|
||||||
if (distance > 0) {
|
if (distance > 0) {
|
||||||
val s1x = s1.x
|
val s1x = s1.p.x
|
||||||
val s1y = s1.y
|
val s1y = s1.p.y
|
||||||
val s1z = s1.z
|
val s1z = s1.p.z
|
||||||
val v = Vector3.Unit(Vector3(s2.x - s1x, s2.y - s1y, s2.z - s1z))
|
val v = Vector3.Unit(Vector3(s2.p.x - s1x, s2.p.y - s1y, s2.p.z - s1z))
|
||||||
val s1d = v * s1.radius
|
val s1d = v * s1.radius
|
||||||
val s2d = v * (s1.radius + distance)
|
val s2d = v * (s1.radius + distance)
|
||||||
Some(Segment3D(s1x + s1d.x, s1y + s1d.y, s1y + s1d.y, s1x + s2d.x, s1y + s2d.y, s1y + s2d.y))
|
Some(Segment3D(s1x + s1d.x, s1y + s1d.y, s1y + s1d.y, s1x + s2d.x, s1y + s2d.y, s1y + s2d.y))
|
||||||
|
|
@ -258,8 +258,8 @@ object Closest {
|
||||||
}
|
}
|
||||||
|
|
||||||
def apply(line : Line3D, sphere : Sphere): Option[Segment3D] = {
|
def apply(line : Line3D, sphere : Sphere): Option[Segment3D] = {
|
||||||
val sphereAsPoint = Vector3(sphere.x, sphere.y, sphere.z)
|
val sphereAsPoint = Vector3(sphere.p.x, sphere.p.y, sphere.p.z)
|
||||||
val lineAsPoint = Vector3(line.x, line.y, line.z)
|
val lineAsPoint = Vector3(line.p.x, line.p.y, line.p.z)
|
||||||
val direct = sphereAsPoint - lineAsPoint
|
val direct = sphereAsPoint - lineAsPoint
|
||||||
val projectionOfDirect = line.d * Vector3.DotProduct(direct, line.d)
|
val projectionOfDirect = line.d * Vector3.DotProduct(direct, line.d)
|
||||||
val heightFromProjection = projectionOfDirect - direct
|
val heightFromProjection = projectionOfDirect - direct
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,30 @@ package net.psforever.objects.geometry
|
||||||
|
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
|
|
||||||
|
trait PrimitiveGeometry {
|
||||||
|
def center: Point
|
||||||
|
|
||||||
|
def pointOnOutside(line: Line) : Point = pointOnOutside(line.d)
|
||||||
|
|
||||||
|
def pointOnOutside(v: Vector3) : Point
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Geometry2D extends PrimitiveGeometry {
|
||||||
|
def center: Point2D
|
||||||
|
|
||||||
|
def pointOnOutside(v: Vector3): Point2D = center
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Geometry3D extends PrimitiveGeometry {
|
||||||
|
def center: Point3D
|
||||||
|
|
||||||
|
def pointOnOutside(v: Vector3): Point3D = center
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Point {
|
||||||
|
def asVector3: Vector3
|
||||||
|
}
|
||||||
|
|
||||||
trait Slope {
|
trait Slope {
|
||||||
def d: Vector3
|
def d: Vector3
|
||||||
|
|
||||||
|
|
@ -15,52 +39,186 @@ trait Line extends Slope {
|
||||||
mag - 0.05f < 1f && mag + 0.05f > 1f
|
mag - 0.05f < 1f && mag + 0.05f > 1f
|
||||||
}, "not a unit vector")
|
}, "not a unit vector")
|
||||||
|
|
||||||
|
def p: Point
|
||||||
|
|
||||||
def length: Float = Float.PositiveInfinity
|
def length: Float = Float.PositiveInfinity
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Segment extends Slope {
|
trait Segment extends Slope {
|
||||||
|
def p1: Point
|
||||||
|
|
||||||
|
def p2: Point
|
||||||
|
|
||||||
def length: Float = Vector3.Magnitude(d)
|
def length: Float = Vector3.Magnitude(d)
|
||||||
|
|
||||||
|
def asLine: PrimitiveGeometry
|
||||||
}
|
}
|
||||||
|
|
||||||
final case class Line2D(x: Float, y: Float, d: Vector3) extends Line
|
final case class Point2D(x: Float, y: Float) extends Geometry2D with Point {
|
||||||
|
def center: Point2D = this
|
||||||
|
|
||||||
|
def asVector3: Vector3 = Vector3(x, y, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
object Point2D {
|
||||||
|
def apply(): Point2D = Point2D(0, 0)
|
||||||
|
|
||||||
|
def apply(v: Vector3): Point2D = Point2D(v.x, v.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
final case class Ray2D(p: Point2D, d: Vector3) extends Geometry2D with Line {
|
||||||
|
def center: Point2D = p
|
||||||
|
}
|
||||||
|
|
||||||
|
object Ray2D {
|
||||||
|
def apply(x: Float, y: Float, d: Vector3): Ray2D = Ray2D(Point2D(x, y), d)
|
||||||
|
}
|
||||||
|
|
||||||
|
final case class Line2D(p: Point2D, d: Vector3) extends Geometry2D with Line {
|
||||||
|
def center: Point2D = p
|
||||||
|
}
|
||||||
|
|
||||||
object Line2D {
|
object Line2D {
|
||||||
|
def apply(ax: Float, ay: Float, d: Vector3): Line2D = {
|
||||||
|
Line2D(Point2D(ax, ay), d)
|
||||||
|
}
|
||||||
|
|
||||||
def apply(ax: Float, ay: Float, bx: Float, by: Float): Line2D = {
|
def apply(ax: Float, ay: Float, bx: Float, by: Float): Line2D = {
|
||||||
Line2D(ax, ay, Vector3.Unit(Vector3(bx-ax, by-ay, 0)))
|
Line2D(Point2D(ax, ay), Vector3.Unit(Vector3(bx-ax, by-ay, 0)))
|
||||||
|
}
|
||||||
|
|
||||||
|
def apply(p1: Point2D, p2: Point2D): Line2D = {
|
||||||
|
Line2D(p1, Vector3.Unit(Vector3(p2.x-p1.x, p2.y-p1.y, 0)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final case class Segment2D(ax: Float, ay: Float, bx: Float, by: Float) extends Segment {
|
final case class Segment2D(p1: Point2D, p2: Point2D) extends Geometry2D with Segment {
|
||||||
def d: Vector3 = Vector3(bx - ax, by - ay, 0)
|
def center: Point2D = Point2D(d * 0.5f)
|
||||||
|
|
||||||
|
def d: Vector3 = p2.asVector3 - p1.asVector3
|
||||||
|
|
||||||
|
def asLine: Line2D = Line2D(p1, Vector3.Unit(d))
|
||||||
}
|
}
|
||||||
|
|
||||||
object Segment2D {
|
object Segment2D {
|
||||||
def apply(x: Float, y: Float, z: Float, d: Vector3): Segment2D = {
|
def apply(ax: Float, ay: Float, bx: Float, by: Float): Segment2D = {
|
||||||
|
Segment2D(Point2D(ax, ay), Point2D(bx, by))
|
||||||
|
}
|
||||||
|
|
||||||
|
def apply(x: Float, y: Float, d: Vector3): Segment2D = {
|
||||||
Segment2D(x, y, x + d.x, y + d.y)
|
Segment2D(x, y, x + d.x, y + d.y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final case class Circle(x: Float, y: Float, radius: Float)
|
final case class Circle(p: Point2D, radius: Float) extends Geometry2D {
|
||||||
|
def center : Point2D = p
|
||||||
|
|
||||||
object Circle {
|
override def pointOnOutside(v: Vector3) : Point2D = {
|
||||||
def apply(radius: Float): Circle = Circle(0f, 0f, radius)
|
val slope = Vector3.Unit(v)
|
||||||
}
|
val pointOnRim = p.asVector3 + slope * radius
|
||||||
|
Point2D(pointOnRim.x, pointOnRim.y)
|
||||||
final case class Line3D(x: Float, y: Float, z: Float, d: Vector3) extends Line
|
|
||||||
|
|
||||||
final case class Segment3D(ax: Float, ay: Float, az: Float, bx: Float, by: Float, bz: Float) extends Segment {
|
|
||||||
def d: Vector3 = Vector3(bx - ax, by - ay, bz - az)
|
|
||||||
}
|
|
||||||
|
|
||||||
object Segment3D {
|
|
||||||
def apply(x: Float, y: Float, z: Float, d: Vector3): Segment3D = {
|
|
||||||
Segment3D(x, y, z, z+d.x, y+d.y, z+d.z)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final case class Sphere(x: Float, y: Float, z: Float, radius: Float)
|
object Circle {
|
||||||
|
def apply(radius: Float): Circle = Circle(Point2D(), radius)
|
||||||
|
|
||||||
final case class Cylinder(circle: Circle, z: Float, height: Float)
|
def apply(x: Float, y: Float, radius: Float): Circle = Circle(Point2D(x, y), radius)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
final case class Point3D(x: Float, y: Float, z: Float) extends Geometry3D with Point {
|
||||||
|
def center: Point3D = this
|
||||||
|
|
||||||
|
def asVector3: Vector3 = Vector3(x, y, z)
|
||||||
|
}
|
||||||
|
|
||||||
|
object Point3D {
|
||||||
|
def apply(): Point3D = Point3D(0,0,0)
|
||||||
|
|
||||||
|
def apply(v: Vector3): Point3D = Point3D(v.x, v.y, v.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
final case class Ray3D(p: Point3D, d: Vector3) extends Geometry3D with Line {
|
||||||
|
def center: Point3D = p
|
||||||
|
}
|
||||||
|
|
||||||
|
object Ray3D {
|
||||||
|
def apply(x: Float, y: Float, z: Float, d: Vector3): Ray3D = Ray3D(Point3D(x,y,z), d)
|
||||||
|
}
|
||||||
|
|
||||||
|
final case class Line3D(p: Point3D, d: Vector3) extends Geometry3D with Line {
|
||||||
|
def center: Point3D = p
|
||||||
|
}
|
||||||
|
|
||||||
|
object Line3D {
|
||||||
|
def apply(x: Float, y: Float, z: Float, d: Vector3): Line3D = {
|
||||||
|
Line3D(Point3D(x,y,z), d)
|
||||||
|
}
|
||||||
|
|
||||||
|
def apply(ax: Float, ay: Float, az: Float, bx: Float, by: Float, bz: Float): Line3D = {
|
||||||
|
Line3D(Point3D(ax, ay, az), Vector3.Unit(Vector3(bx-ax, by-ay, bz-az)))
|
||||||
|
}
|
||||||
|
|
||||||
|
def apply(p1: Point3D, p2: Point3D): Line3D = {
|
||||||
|
Line3D(p1, Vector3.Unit(Vector3(p2.x-p1.x, p2.y-p1.y, p2.z-p1.z)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final case class Segment3D(p1: Point3D, p2: Point3D) extends Geometry3D with Segment {
|
||||||
|
def center: Point3D = Point3D(d * 0.5f)
|
||||||
|
|
||||||
|
def d: Vector3 = p2.asVector3 - p1.asVector3
|
||||||
|
|
||||||
|
def asLine: Line3D = Line3D(p1, Vector3.Unit(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
object Segment3D {
|
||||||
|
def apply(ax: Float, ay: Float, az: Float, bx: Float, by: Float, bz: Float): Segment3D = {
|
||||||
|
Segment3D(Point3D(ax, ay, az), Point3D(bx, by, bz))
|
||||||
|
}
|
||||||
|
|
||||||
|
def apply(x: Float, y: Float, z: Float, d: Vector3): Segment3D = {
|
||||||
|
Segment3D(Point3D(x, y, z), Point3D(x + d.x, y + d.y, z + d.z))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final case class Sphere(p: Point3D, radius: Float) extends Geometry3D {
|
||||||
|
def center: Point3D = p
|
||||||
|
|
||||||
|
override def pointOnOutside(v: Vector3): Point3D = {
|
||||||
|
val slope = Vector3.Unit(v)
|
||||||
|
val mult = radius / math.sqrt(slope.x * slope.x + slope.y * slope.y + slope.z * slope.z)
|
||||||
|
val pointOnSurface = center.asVector3 + slope * mult.toFloat
|
||||||
|
Point3D(pointOnSurface.x, pointOnSurface.y, pointOnSurface.z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Sphere {
|
||||||
|
def apply(radius: Float): Sphere = Sphere(Point3D(), radius)
|
||||||
|
|
||||||
|
def apply(x: Float, y: Float, z: Float, radius: Float): Sphere = Sphere(Point3D(x,y,z), radius)
|
||||||
|
|
||||||
|
def apply(v: Vector3, radius: Float): Sphere = Sphere(Point3D(v), radius)
|
||||||
|
}
|
||||||
|
|
||||||
|
final case class Cylinder(circle: Circle, z: Float, height: Float) extends Geometry3D {
|
||||||
|
def center: Point3D = Point3D(circle.p.x, circle.p.y, z + height * 0.5f)
|
||||||
|
|
||||||
|
override def pointOnOutside(v: Vector3): Point3D = {
|
||||||
|
val centerVector = center.asVector3
|
||||||
|
val slope = Vector3.Unit(v)
|
||||||
|
val mult = circle.radius / math.sqrt(slope.x * slope.x + slope.y * slope.y)
|
||||||
|
val pointOnRim = centerVector + slope * mult.toFloat
|
||||||
|
val point = if (z >= pointOnRim.z && pointOnRim.z <= height) { //side
|
||||||
|
pointOnRim
|
||||||
|
} else { //top or base
|
||||||
|
val rise = height * 0.5f / slope.z
|
||||||
|
centerVector + slope * rise
|
||||||
|
}
|
||||||
|
Point3D(point.x, point.y, point.z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object Cylinder {
|
object Cylinder {
|
||||||
def apply(x: Float, y: Float, z: Float, radius: Float, height: Float): Cylinder = {
|
def apply(x: Float, y: Float, z: Float, radius: Float, height: Float): Cylinder = {
|
||||||
|
|
@ -68,10 +226,6 @@ object Cylinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object Sphere {
|
|
||||||
def apply(p: Vector3, radius: Float): Sphere = Sphere(p.x, p.y, p.z, radius)
|
|
||||||
}
|
|
||||||
|
|
||||||
object Geometry {
|
object Geometry {
|
||||||
def equalFloats(value1: Float, value2: Float, off: Float = 0.001f): Boolean = {
|
def equalFloats(value1: Float, value2: Float, off: Float = 0.001f): Boolean = {
|
||||||
val diff = value1 - value2
|
val diff = value1 - value2
|
||||||
|
|
|
||||||
113
src/main/scala/net/psforever/objects/geometry/GeometryForm.scala
Normal file
113
src/main/scala/net/psforever/objects/geometry/GeometryForm.scala
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
// Copyright (c) 2021 PSForever
|
||||||
|
package net.psforever.objects.geometry
|
||||||
|
|
||||||
|
import net.psforever.objects.ballistics.{PlayerSource, SourceEntry}
|
||||||
|
import net.psforever.objects.{GlobalDefinitions, PlanetSideGameObject, Player}
|
||||||
|
import net.psforever.types.ExoSuitType
|
||||||
|
|
||||||
|
object GeometryForm {
|
||||||
|
/** this point can not be used for purposes of geometric representation */
|
||||||
|
lazy val invalidPoint: Point3D = Point3D(Float.MinValue, Float.MinValue, Float.MinValue)
|
||||||
|
/** this circle can not be used for purposes of geometric representation */
|
||||||
|
lazy val invalidCircle: Circle = Circle(Point2D(invalidPoint.asVector3), 0)
|
||||||
|
/** this cylinder can not be used for purposes of geometric representation */
|
||||||
|
lazy val invalidCylinder: Cylinder = Cylinder(invalidCircle, Float.MinValue, 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The geometric representation is the entity's centroid.
|
||||||
|
* @param o the entity
|
||||||
|
* @return the representation
|
||||||
|
*/
|
||||||
|
def representByPoint()(o: Any): Geometry3D = {
|
||||||
|
o match {
|
||||||
|
case p: PlanetSideGameObject => Point3D(p.Position)
|
||||||
|
case s: SourceEntry => Point3D(s.Position)
|
||||||
|
case _ => invalidPoint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The geometric representation is the a sphere around the entity's centroid.
|
||||||
|
* @param radius how wide a hemisphere is
|
||||||
|
* @param o the entity
|
||||||
|
* @return the representation
|
||||||
|
*/
|
||||||
|
def representBySphere(radius: Float)(o: Any): Geometry3D = {
|
||||||
|
o match {
|
||||||
|
case p: PlanetSideGameObject => Sphere(p.Position, radius)
|
||||||
|
case s: SourceEntry => Sphere(s.Position, radius)
|
||||||
|
case _ => Sphere(invalidPoint, radius)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The geometric representation is the a cylinder around the entity's base.
|
||||||
|
* @param radius half the distance across
|
||||||
|
* @param height how tall the cylinder is (the distance of the top to the base)
|
||||||
|
* @param o the entity
|
||||||
|
* @return the representation
|
||||||
|
*/
|
||||||
|
def representByCylinder(radius: Float, height: Float)(o: Any): Geometry3D = {
|
||||||
|
o match {
|
||||||
|
case p: PlanetSideGameObject => Cylinder(Circle(p.Position.x, p.Position.y, radius), p.Position.z, height)
|
||||||
|
case s: SourceEntry => Cylinder(Circle(s.Position.x, s.Position.y, radius), s.Position.z, height)
|
||||||
|
case _ => invalidCylinder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The geometric representation is the a cylinder around the entity's base
|
||||||
|
* if the target represents a player entity.
|
||||||
|
* @param radius a measure of the player's bulk
|
||||||
|
* @param o the entity
|
||||||
|
* @return the representation
|
||||||
|
*/
|
||||||
|
def representPlayerByCylinder(radius: Float)(o: Any): Geometry3D = {
|
||||||
|
o match {
|
||||||
|
case p: Player =>
|
||||||
|
val radialOffset = if(p.ExoSuit == ExoSuitType.MAX) 0.25f else 0f
|
||||||
|
Cylinder(
|
||||||
|
Circle(p.Position.x, p.Position.y, radius + radialOffset),
|
||||||
|
p.Position.z,
|
||||||
|
GlobalDefinitions.MaxDepth(p)
|
||||||
|
)
|
||||||
|
case p: PlayerSource =>
|
||||||
|
val radialOffset = if(p.ExoSuit == ExoSuitType.MAX) 0.25f else 0f
|
||||||
|
Cylinder(
|
||||||
|
Circle(p.Position.x, p.Position.y, radius + radialOffset),
|
||||||
|
p.Position.z,
|
||||||
|
GlobalDefinitions.avatar.MaxDepth
|
||||||
|
)
|
||||||
|
case _ =>
|
||||||
|
invalidCylinder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The geometric representation is the a cylinder around the entity's base
|
||||||
|
* as if the target is displaced from the ground at an expected (fixed?) distance.
|
||||||
|
* @param radius half the distance across
|
||||||
|
* @param height how tall the cylinder is (the distance of the top to the base)
|
||||||
|
* @param hoversAt how far off the base coordinates the actual cylinder begins
|
||||||
|
* @param o the entity
|
||||||
|
* @return the representation
|
||||||
|
*/
|
||||||
|
def representHoveringEntityByCylinder(radius: Float, height: Float, hoversAt: Float)(o: Any): Geometry3D = {
|
||||||
|
o match {
|
||||||
|
case p: PlanetSideGameObject =>
|
||||||
|
Cylinder(
|
||||||
|
Circle(p.Position.x, p.Position.y, radius),
|
||||||
|
p.Position.z + hoversAt,
|
||||||
|
height
|
||||||
|
)
|
||||||
|
case s: SourceEntry =>
|
||||||
|
Cylinder(
|
||||||
|
Circle(s.Position.x, s.Position.y, radius),
|
||||||
|
s.Position.z + hoversAt,
|
||||||
|
height
|
||||||
|
)
|
||||||
|
case _ =>
|
||||||
|
invalidCylinder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,7 +13,7 @@ object Intersection {
|
||||||
def apply(line1: Line2D, line2: Line2D): Boolean = {
|
def apply(line1: Line2D, line2: Line2D): Boolean = {
|
||||||
line1.d != line2.d || {
|
line1.d != line2.d || {
|
||||||
//parallel or antiparallel?
|
//parallel or antiparallel?
|
||||||
val u = Vector3.Unit(Vector3(line2.x - line1.x, line2.y - line1.y, 0))
|
val u = Vector3.Unit(Vector3(line2.p.x - line1.p.x, line2.p.y - line1.p.y, 0))
|
||||||
u == Vector3.Zero || line1.d == u || line1.d == Vector3.neg(u)
|
u == Vector3.Zero || line1.d == u || line1.d == Vector3.neg(u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -59,14 +59,14 @@ object Intersection {
|
||||||
*/
|
*/
|
||||||
def apply(line1: Segment2D, line2: Segment2D): Boolean = {
|
def apply(line1: Segment2D, line2: Segment2D): Boolean = {
|
||||||
//setup
|
//setup
|
||||||
val ln1ax = line1.ax
|
val ln1ax = line1.p1.x
|
||||||
val ln1ay = line1.ay
|
val ln1ay = line1.p1.y
|
||||||
val ln1bx = line1.bx
|
val ln1bx = line1.p2.x
|
||||||
val ln1by = line1.by
|
val ln1by = line1.p2.y
|
||||||
val ln2ax = line2.ax
|
val ln2ax = line2.p1.x
|
||||||
val ln2ay = line2.ay
|
val ln2ay = line2.p1.y
|
||||||
val ln2bx = line2.bx
|
val ln2bx = line2.p2.x
|
||||||
val ln2by = line2.by
|
val ln2by = line2.p2.y
|
||||||
val ln1_ln2a = orientationOfPoints(ln1ax, ln1ay, ln1bx, ln1by, ln2ax, ln2ay)
|
val ln1_ln2a = orientationOfPoints(ln1ax, ln1ay, ln1bx, ln1by, ln2ax, ln2ay)
|
||||||
val ln1_ln2b = orientationOfPoints(ln1ax, ln1ay, ln1bx, ln1by, ln2bx, ln2by)
|
val ln1_ln2b = orientationOfPoints(ln1ax, ln1ay, ln1bx, ln1by, ln2bx, ln2by)
|
||||||
val ln2_ln1a = orientationOfPoints(ln2ax, ln2ay, ln2bx, ln2by, ln1ax, ln1ay)
|
val ln2_ln1a = orientationOfPoints(ln2ax, ln2ay, ln2bx, ln2by, ln1ax, ln1ay)
|
||||||
|
|
@ -93,7 +93,7 @@ object Intersection {
|
||||||
}
|
}
|
||||||
|
|
||||||
def apply(c1: Circle, c2 : Circle): Boolean = {
|
def apply(c1: Circle, c2 : Circle): Boolean = {
|
||||||
Vector3.Magnitude(Vector3(c1.x - c2.x, c1.y - c2.y, 0)) <= c1.radius + c2.radius
|
Vector3.Magnitude(Vector3(c1.p.x - c2.p.x, c1.p.y - c2.p.y, 0)) <= c1.radius + c2.radius
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -111,9 +111,9 @@ object Intersection {
|
||||||
def apply(s1: Sphere, s2 : Sphere): Boolean = {
|
def apply(s1: Sphere, s2 : Sphere): Boolean = {
|
||||||
Vector3.Magnitude(
|
Vector3.Magnitude(
|
||||||
Vector3(
|
Vector3(
|
||||||
s1.x - s2.x,
|
s1.p.x - s2.p.x,
|
||||||
s1.y - s2.y,
|
s1.p.y - s2.p.y,
|
||||||
s1.z - s2.z
|
s1.p.z - s2.p.z
|
||||||
)
|
)
|
||||||
) <= s1.radius + s2.radius
|
) <= s1.radius + s2.radius
|
||||||
}
|
}
|
||||||
|
|
@ -128,17 +128,17 @@ object Intersection {
|
||||||
val cylinderCircleRadius = cylinderCircle.radius
|
val cylinderCircleRadius = cylinderCircle.radius
|
||||||
val cylinderTop = cylinder.z + cylinder.height
|
val cylinderTop = cylinder.z + cylinder.height
|
||||||
val sphereRadius = sphere.radius
|
val sphereRadius = sphere.radius
|
||||||
val sphereBase = sphere.z - sphereRadius
|
val sphereBase = sphere.p.z - sphereRadius
|
||||||
val sphereTop = sphere.z + sphereRadius
|
val sphereTop = sphere.p.z + sphereRadius
|
||||||
if (apply(cylinderCircle, Circle(sphere.x, sphere.y, sphereRadius)) &&
|
if (apply(cylinderCircle, Circle(sphere.p.x, sphere.p.y, sphereRadius)) &&
|
||||||
((sphereTop >= cylinder.z && sphereBase <= cylinderTop) ||
|
((sphereTop >= cylinder.z && sphereBase <= cylinderTop) ||
|
||||||
(cylinderTop >= sphereBase && cylinder.z <= sphereTop))) {
|
(cylinderTop >= sphereBase && cylinder.z <= sphereTop))) {
|
||||||
// potential intersection ...
|
// potential intersection ...
|
||||||
val sphereAsPoint = Vector3(sphere.x, sphere.y, sphere.z)
|
val sphereAsPoint = Vector3(sphere.p.x, sphere.p.y, sphere.p.z)
|
||||||
val cylinderAsPoint = Vector3(cylinderCircle.x, cylinderCircle.y, cylinder.z)
|
val cylinderAsPoint = Vector3(cylinderCircle.p.x, cylinderCircle.p.y, cylinder.z)
|
||||||
val segmentFromCylinderToSphere = sphereAsPoint - cylinderAsPoint
|
val segmentFromCylinderToSphere = sphereAsPoint - cylinderAsPoint
|
||||||
val segmentFromCylinderToSphereXY = segmentFromCylinderToSphere.xy
|
val segmentFromCylinderToSphereXY = segmentFromCylinderToSphere.xy
|
||||||
if ((cylinder.z <= sphere.z && sphere.z <= cylinderTop) ||
|
if ((cylinder.z <= sphere.p.z && sphere.p.z <= cylinderTop) ||
|
||||||
Vector3.MagnitudeSquared(segmentFromCylinderToSphereXY) <= cylinderCircleRadius * cylinderCircleRadius) {
|
Vector3.MagnitudeSquared(segmentFromCylinderToSphereXY) <= cylinderCircleRadius * cylinderCircleRadius) {
|
||||||
true // top or bottom of sphere, or widest part of the sphere, must interact with the cylinder
|
true // top or bottom of sphere, or widest part of the sphere, must interact with the cylinder
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,11 @@ import net.psforever.objects.PlanetSideGameObject
|
||||||
import net.psforever.objects.ballistics.SourceEntry
|
import net.psforever.objects.ballistics.SourceEntry
|
||||||
import net.psforever.objects.definition.ObjectDefinition
|
import net.psforever.objects.definition.ObjectDefinition
|
||||||
import net.psforever.objects.vital.{Vitality, VitalityDefinition}
|
import net.psforever.objects.vital.{Vitality, VitalityDefinition}
|
||||||
import net.psforever.objects.vital.base.{DamageReason, DamageResolution}
|
import net.psforever.objects.vital.base.{DamageModifiers, DamageReason, DamageResolution}
|
||||||
import net.psforever.objects.vital.interaction.DamageResult
|
import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult}
|
||||||
import net.psforever.objects.vital.prop.DamageWithPosition
|
import net.psforever.objects.vital.prop.DamageWithPosition
|
||||||
import net.psforever.objects.vital.resolution.DamageAndResistance
|
import net.psforever.objects.vital.resolution.DamageAndResistance
|
||||||
|
import net.psforever.objects.zones.Zone
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrapper for a "damage source" in damage calculations
|
* A wrapper for a "damage source" in damage calculations
|
||||||
|
|
@ -48,3 +49,48 @@ final case class ExplodingEntityReason(
|
||||||
/** the entity that exploded is the source of the damage */
|
/** the entity that exploded is the source of the damage */
|
||||||
override def attribution: Int = definition.ObjectId
|
override def attribution: Int = definition.ObjectId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object ExplodingDamageModifiers {
|
||||||
|
trait Mod extends DamageModifiers.Mod {
|
||||||
|
def calculate(damage : Int, data : DamageInteraction, cause : DamageReason) : Int = {
|
||||||
|
cause match {
|
||||||
|
case o: ExplodingEntityReason => calculate(damage, data, o)
|
||||||
|
case _ => damage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def calculate(damage : Int, data : DamageInteraction, cause : ExplodingEntityReason) : Int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A variation of the normal radial damage degradation
|
||||||
|
* that uses the geometric representations of the exploding entity and of the affected target
|
||||||
|
* in its calculations that determine the distance between them.
|
||||||
|
* @see `DamageModifierFunctions.RadialDegrade`
|
||||||
|
*/
|
||||||
|
case object ExplodingRadialDegrade extends ExplodingDamageModifiers.Mod {
|
||||||
|
def calculate(damage: Int, data: DamageInteraction, cause: ExplodingEntityReason): Int = {
|
||||||
|
cause.source match {
|
||||||
|
case withPosition: DamageWithPosition =>
|
||||||
|
val distance = math.sqrt(Zone.distanceCheck(
|
||||||
|
cause.entity.Definition.asInstanceOf[ObjectDefinition].Geometry(cause.entity),
|
||||||
|
data.target.Definition.Geometry(data.target)
|
||||||
|
))
|
||||||
|
val radius = withPosition.DamageRadius
|
||||||
|
val radiusMin = withPosition.DamageRadiusMin
|
||||||
|
if (distance <= radiusMin) {
|
||||||
|
damage
|
||||||
|
} else if (distance <= radius) {
|
||||||
|
//damage - (damage * profile.DamageAtEdge * (distance - radiusMin) / (radius - radiusMin)).toInt
|
||||||
|
val base = withPosition.DamageAtEdge
|
||||||
|
val radi = radius - radiusMin
|
||||||
|
(damage * ((1 - base) * ((radi - (distance - radiusMin)) / radi) + base)).toInt
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
case _ =>
|
||||||
|
damage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import akka.actor.typed
|
||||||
import net.psforever.actors.session.AvatarActor
|
import net.psforever.actors.session.AvatarActor
|
||||||
import net.psforever.actors.zone.ZoneActor
|
import net.psforever.actors.zone.ZoneActor
|
||||||
import net.psforever.objects.avatar.Avatar
|
import net.psforever.objects.avatar.Avatar
|
||||||
|
import net.psforever.objects.geometry.Geometry3D
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||||
import net.psforever.objects.vehicles.UtilityType
|
import net.psforever.objects.vehicles.UtilityType
|
||||||
|
|
@ -1175,7 +1176,7 @@ object Zone {
|
||||||
* Two game entities are considered "near" each other if they are within a certain distance of one another.
|
* Two game entities are considered "near" each other if they are within a certain distance of one another.
|
||||||
* A default function literal mainly used for `causesExplosion`.
|
* A default function literal mainly used for `causesExplosion`.
|
||||||
* @see `causeExplosion`
|
* @see `causeExplosion`
|
||||||
* @see `Vector3.DistanceSquare`
|
* @see `ObjectDefinition.Geometry`
|
||||||
* @param obj1 a game entity
|
* @param obj1 a game entity
|
||||||
* @param obj2 a game entity
|
* @param obj2 a game entity
|
||||||
* @param maxDistance the square of the maximum distance permissible between game entities
|
* @param maxDistance the square of the maximum distance permissible between game entities
|
||||||
|
|
@ -1183,7 +1184,35 @@ object Zone {
|
||||||
* @return `true`, if the target entities are near to each other;
|
* @return `true`, if the target entities are near to each other;
|
||||||
* `false`, otherwise
|
* `false`, otherwise
|
||||||
*/
|
*/
|
||||||
private def distanceCheck(obj1: PlanetSideGameObject, obj2: PlanetSideGameObject, maxDistance: Float): Boolean = {
|
def distanceCheck(obj1: PlanetSideGameObject, obj2: PlanetSideGameObject, maxDistance: Float): Boolean = {
|
||||||
Vector3.DistanceSquared(obj1.Position, obj2.Position) <= maxDistance
|
distanceCheck(obj1.Definition.Geometry(obj1), obj2.Definition.Geometry(obj2), maxDistance)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Two game entities are considered "near" each other if they are within a certain distance of one another.
|
||||||
|
* @param g1 the geometric representation of a game entity
|
||||||
|
* @param g2 the geometric representation of a game entity
|
||||||
|
* @param maxDistance the square of the maximum distance permissible between game entities
|
||||||
|
* before they are no longer considered "near"
|
||||||
|
* @return `true`, if the target entities are near to each other;
|
||||||
|
* `false`, otherwise
|
||||||
|
*/
|
||||||
|
def distanceCheck(g1: Geometry3D, g2: Geometry3D, maxDistance: Float): Boolean = {
|
||||||
|
distanceCheck(g1, g2) <= maxDistance
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Two game entities are considered "near" each other if they are within a certain distance of one another.
|
||||||
|
* @see `PrimitiveGeometry.pointOnOutside`
|
||||||
|
* @see `Vector3.DistanceSquared`
|
||||||
|
* @see `Vector3.neg`
|
||||||
|
* @see `Vector3.Unit`
|
||||||
|
* @param g1 the geometric representation of a game entity
|
||||||
|
* @param g2 the geometric representation of a game entity
|
||||||
|
* @return the crude distance between the two geometric representations
|
||||||
|
*/
|
||||||
|
def distanceCheck(g1: Geometry3D, g2: Geometry3D): Float = {
|
||||||
|
val dir = Vector3.Unit(g2.center.asVector3 - g1.center.asVector3)
|
||||||
|
val point1 = g1.pointOnOutside(dir).asVector3
|
||||||
|
val point2 = g2.pointOnOutside(Vector3.neg(dir)).asVector3
|
||||||
|
Vector3.DistanceSquared(point1, point2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue