diff --git a/examples/starting-3d-grand-theft-auto/starting-3d-grand-theft-auto.json b/examples/starting-3d-grand-theft-auto/starting-3d-grand-theft-auto.json index 58449cd91..27b8dd02c 100644 --- a/examples/starting-3d-grand-theft-auto/starting-3d-grand-theft-auto.json +++ b/examples/starting-3d-grand-theft-auto/starting-3d-grand-theft-auto.json @@ -2237,7 +2237,7 @@ }, { "type": { - "value": "Distance" + "value": "Distance3D" }, "parameters": [ "Vehicles", diff --git a/examples/starting-3d-tank/starting-3d-tank.json b/examples/starting-3d-tank/starting-3d-tank.json index 951c62993..4f2766be8 100644 --- a/examples/starting-3d-tank/starting-3d-tank.json +++ b/examples/starting-3d-tank/starting-3d-tank.json @@ -1759,8 +1759,8 @@ "parameters": [ "", "Bullet", - "PlayerTank.CenterX() + XFromAngleAndDistance(PlayerTank.Angle() + PlayerTank.TopRotation(), PlayerTank.CannonWidth())", - "PlayerTank.CenterY() + YFromAngleAndDistance(PlayerTank.Angle() + PlayerTank.TopRotation(), PlayerTank.CannonWidth())", + "PlayerTank.MuzzleX()", + "PlayerTank.MuzzleY()", "" ] }, @@ -1772,28 +1772,28 @@ "Bullet", "Object3D", "=", - "(PlayerTank.Object3D::CenterZ()) + sin(ToRad(-1 * PlayerTank.CannonAngle() - PlayerTank.Object3D::RotationY() * cos(ToRad(PlayerTank.TopRotation())) - PlayerTank.Object3D::RotationX() * sin(ToRad(PlayerTank.TopRotation())))) * PlayerTank.CannonWidth()" + "PlayerTank.MuzzleZ()" ] }, { "type": { - "value": "Scene3D::Base3DBehavior::SetRotationY" + "value": "SetAngle" }, "parameters": [ "Bullet", - "Object3D", "=", - "(PlayerTank.CannonAngle() + PlayerTank.Object3D::RotationY() * cos(ToRad(PlayerTank.TopRotation())) - PlayerTank.Object3D::RotationX() * sin(ToRad(PlayerTank.TopRotation())))" + "ToDeg(atan2(PlayerTank.AimDirectionY(), PlayerTank.AimDirectionX()))" ] }, { "type": { - "value": "SetAngle" + "value": "Scene3D::Base3DBehavior::SetRotationY" }, "parameters": [ "Bullet", + "Object3D", "=", - "PlayerTank.TopRotation() + PlayerTank.Angle()" + "-ToDeg(asin(clamp(PlayerTank.AimDirectionZ(), -1, 1)))" ] }, { @@ -1821,15 +1821,14 @@ }, { "type": { - "value": "Physics3D::Physics3DBehavior::ApplyImpulseTowardPosition" + "value": "Physics3D::Physics3DBehavior::ApplyImpulseAtCenter" }, "parameters": [ "Bullet", "Physics3D", - "15", - "Bullet.X() + XFromAngleAndDistance(PlayerTank.Angle() + PlayerTank.TopRotation(), 20)", - "Bullet.Y() + YFromAngleAndDistance(PlayerTank.Angle() + PlayerTank.TopRotation(), 20)", - "Bullet.Object3D::Z() + sin(ToRad(-1 * Bullet.Object3D::RotationY())) * 10" + "15 * PlayerTank.AimDirectionX()", + "15 * PlayerTank.AimDirectionY()", + "15 * PlayerTank.AimDirectionZ()" ] }, { @@ -1961,7 +1960,7 @@ "conditions": [ { "type": { - "value": "Distance" + "value": "Distance3D" }, "parameters": [ "Target", @@ -1979,7 +1978,7 @@ "parameters": [ "Target", "Physics3D", - "-5 * (300 - (Target.Distance(Bullet)))", + "-5 * (300 - Target.Object3D::Distance3D(Bullet))", "Bullet.X() + XFromAngleAndDistance(Target.AngleToObject(Bullet), 500)", "Bullet.Y() + YFromAngleAndDistance(Target.AngleToObject(Bullet), 500)", "0" @@ -2390,13 +2389,7 @@ "authorIds": [], "dependencies": [], "globalVariables": [], - "sceneVariables": [ - { - "name": "CannonWidth", - "type": "number", - "value": 0 - } - ], + "sceneVariables": [], "eventsFunctions": [], "eventsFunctionsFolderStructure": { "folderName": "__ROOT" @@ -2716,10 +2709,10 @@ "objectGroups": [] }, { - "description": "Return the distance between the end of the cannon and the center of the TankTop object", - "fullName": "Return CannonWidth", + "description": "Return the X position of the end of the cannon, in the scene.", + "fullName": "Muzzle position (X)", "functionType": "Expression", - "name": "CannonWidth", + "name": "MuzzleX", "sentence": "", "events": [ { @@ -2728,19 +2721,185 @@ "actions": [ { "type": { - "value": "TankConfiguration::TankTop::CannonInfo" + "value": "SetReturnNumber" }, "parameters": [ - "TankTop_Combined", - "" + "Object.ToParentX(TankTop_Combined.MuzzleX(), TankTop_Combined.MuzzleY(), TankTop_Combined.MuzzleZ())" ] - }, + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::CombinedTank", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the Y position of the end of the cannon, in the scene.", + "fullName": "Muzzle position (Y)", + "functionType": "Expression", + "name": "MuzzleY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentY(TankTop_Combined.MuzzleX(), TankTop_Combined.MuzzleY(), TankTop_Combined.MuzzleZ())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::CombinedTank", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the Z position of the end of the cannon, in the scene.", + "fullName": "Muzzle position (Z)", + "functionType": "Expression", + "name": "MuzzleZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ { "type": { "value": "SetReturnNumber" }, "parameters": [ - "CannonWidth" + "Object.ToParentZ(TankTop_Combined.MuzzleX(), TankTop_Combined.MuzzleY(), TankTop_Combined.MuzzleZ())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::CombinedTank", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the X of the direction the cannon points at (a unit vector), in the scene.", + "fullName": "Aim direction (X)", + "functionType": "Expression", + "name": "AimDirectionX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentDirectionX(TankTop_Combined.AimDirectionX(), TankTop_Combined.AimDirectionY(), TankTop_Combined.AimDirectionZ())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::CombinedTank", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the Y of the direction the cannon points at (a unit vector), in the scene.", + "fullName": "Aim direction (Y)", + "functionType": "Expression", + "name": "AimDirectionY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentDirectionY(TankTop_Combined.AimDirectionX(), TankTop_Combined.AimDirectionY(), TankTop_Combined.AimDirectionZ())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::CombinedTank", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the Z of the direction the cannon points at (a unit vector), in the scene.", + "fullName": "Aim direction (Z)", + "functionType": "Expression", + "name": "AimDirectionZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentDirectionZ(TankTop_Combined.AimDirectionX(), TankTop_Combined.AimDirectionY(), TankTop_Combined.AimDirectionZ())" ] } ] @@ -2781,7 +2940,22 @@ ] }, { - "functionName": "CannonWidth" + "functionName": "MuzzleX" + }, + { + "functionName": "MuzzleY" + }, + { + "functionName": "MuzzleZ" + }, + { + "functionName": "AimDirectionX" + }, + { + "functionName": "AimDirectionY" + }, + { + "functionName": "AimDirectionZ" } ] }, @@ -3016,11 +3190,11 @@ "objectGroups": [] }, { - "description": "Record variables related to the TankCannon object", - "fullName": "Record TankCannon information", - "functionType": "Action", - "name": "CannonInfo", - "sentence": "Record information for the TankCannon of _PARAM0_", + "description": "Return the X position of the end of the cannon, in the tank containing the tank top.", + "fullName": "Muzzle position (X)", + "functionType": "Expression", + "name": "MuzzleX", + "sentence": "", "events": [ { "type": "BuiltinCommonInstructions::Standard", @@ -3028,17 +3202,193 @@ "actions": [ { "type": { - "value": "SetNumberVariable" + "value": "SetReturnNumber" }, "parameters": [ - "CannonWidth", - "=", - "TankCanon.Width() + TankTop.Width()/2" + "Object.ToParentX(TankCanon.X() + TankCanon.Object3D::ForwardX() * TankCanon.Width(), TankCanon.Y() + TankCanon.Object3D::ForwardY() * TankCanon.Width(), TankCanon.Object3D::Z() + TankCanon.Object3D::ForwardZ() * TankCanon.Width())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::TankTop", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the Y position of the end of the cannon, in the tank containing the tank top.", + "fullName": "Muzzle position (Y)", + "functionType": "Expression", + "name": "MuzzleY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentY(TankCanon.X() + TankCanon.Object3D::ForwardX() * TankCanon.Width(), TankCanon.Y() + TankCanon.Object3D::ForwardY() * TankCanon.Width(), TankCanon.Object3D::Z() + TankCanon.Object3D::ForwardZ() * TankCanon.Width())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::TankTop", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the Z position of the end of the cannon, in the tank containing the tank top.", + "fullName": "Muzzle position (Z)", + "functionType": "Expression", + "name": "MuzzleZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentZ(TankCanon.X() + TankCanon.Object3D::ForwardX() * TankCanon.Width(), TankCanon.Y() + TankCanon.Object3D::ForwardY() * TankCanon.Width(), TankCanon.Object3D::Z() + TankCanon.Object3D::ForwardZ() * TankCanon.Width())" ] } ] } ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::TankTop", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the X of the direction the cannon points at (a unit vector), in the tank containing the tank top.", + "fullName": "Aim direction (X)", + "functionType": "Expression", + "name": "AimDirectionX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentDirectionX(TankCanon.Object3D::ForwardX(), TankCanon.Object3D::ForwardY(), TankCanon.Object3D::ForwardZ())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::TankTop", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the Y of the direction the cannon points at (a unit vector), in the tank containing the tank top.", + "fullName": "Aim direction (Y)", + "functionType": "Expression", + "name": "AimDirectionY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentDirectionY(TankCanon.Object3D::ForwardX(), TankCanon.Object3D::ForwardY(), TankCanon.Object3D::ForwardZ())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::TankTop", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the Z of the direction the cannon points at (a unit vector), in the tank containing the tank top.", + "fullName": "Aim direction (Z)", + "functionType": "Expression", + "name": "AimDirectionZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentDirectionZ(TankCanon.Object3D::ForwardX(), TankCanon.Object3D::ForwardY(), TankCanon.Object3D::ForwardZ())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, "parameters": [ { "description": "Object", @@ -3057,7 +3407,22 @@ "functionName": "Elevation" }, { - "functionName": "CannonInfo" + "functionName": "MuzzleX" + }, + { + "functionName": "MuzzleY" + }, + { + "functionName": "MuzzleZ" + }, + { + "functionName": "AimDirectionX" + }, + { + "functionName": "AimDirectionY" + }, + { + "functionName": "AimDirectionZ" } ] }, diff --git a/examples/starting-expanded-3d-grand-theft-auto/starting-expanded-3d-grand-theft-auto.json b/examples/starting-expanded-3d-grand-theft-auto/starting-expanded-3d-grand-theft-auto.json index b1838de62..f20c1c91b 100644 --- a/examples/starting-expanded-3d-grand-theft-auto/starting-expanded-3d-grand-theft-auto.json +++ b/examples/starting-expanded-3d-grand-theft-auto/starting-expanded-3d-grand-theft-auto.json @@ -5000,7 +5000,7 @@ }, { "type": { - "value": "Distance" + "value": "Distance3D" }, "parameters": [ "Vehicles", diff --git a/examples/starting-expanded-3d-house-horror/starting-expanded-3d-house-horror.json b/examples/starting-expanded-3d-house-horror/starting-expanded-3d-house-horror.json index 417147e07..cb01b0113 100644 --- a/examples/starting-expanded-3d-house-horror/starting-expanded-3d-house-horror.json +++ b/examples/starting-expanded-3d-house-horror/starting-expanded-3d-house-horror.json @@ -9625,7 +9625,7 @@ "conditions": [ { "type": { - "value": "Distance" + "value": "Distance3D" }, "parameters": [ "Player", @@ -9633,16 +9633,6 @@ "120", "" ] - }, - { - "type": { - "value": "BuiltinCommonInstructions::CompareNumbers" - }, - "parameters": [ - "abs(Player.Object3D::Z() - Key.Object3D::Z())", - "<", - "100" - ] } ], "actions": [ @@ -9715,24 +9705,14 @@ "conditions": [ { "type": { - "value": "Distance" + "value": "Distance3D" }, "parameters": [ "Player", "Door", - "130", + "145", "" ] - }, - { - "type": { - "value": "BuiltinCommonInstructions::CompareNumbers" - }, - "parameters": [ - "abs(Player.Object3D::Z() - Door.Object3D::Z())", - "<", - "100" - ] } ], "actions": [], diff --git a/examples/starting-expanded-3d-tank/starting-expanded-3d-tank.json b/examples/starting-expanded-3d-tank/starting-expanded-3d-tank.json index 524a63ee3..43bb77c61 100644 --- a/examples/starting-expanded-3d-tank/starting-expanded-3d-tank.json +++ b/examples/starting-expanded-3d-tank/starting-expanded-3d-tank.json @@ -2996,8 +2996,8 @@ "parameters": [ "", "Bullet", - "PlayerTank.CenterX() + XFromAngleAndDistance(PlayerTank.Angle() + PlayerTank.TopRotation(), PlayerTank.CannonWidth())", - "PlayerTank.CenterY() + YFromAngleAndDistance(PlayerTank.Angle() + PlayerTank.TopRotation(), PlayerTank.CannonWidth())", + "PlayerTank.MuzzleX()", + "PlayerTank.MuzzleY()", "" ] }, @@ -3009,28 +3009,28 @@ "Bullet", "Object3D", "=", - "(PlayerTank.Object3D::CenterZ()) + sin(ToRad(-1 * PlayerTank.CannonAngle() - PlayerTank.Object3D::RotationY() * cos(ToRad(PlayerTank.TopRotation())) - PlayerTank.Object3D::RotationX() * sin(ToRad(PlayerTank.TopRotation())))) * PlayerTank.CannonWidth()" + "PlayerTank.MuzzleZ()" ] }, { "type": { - "value": "Scene3D::Base3DBehavior::SetRotationY" + "value": "SetAngle" }, "parameters": [ "Bullet", - "Object3D", "=", - "(PlayerTank.CannonAngle() + PlayerTank.Object3D::RotationY() * cos(ToRad(PlayerTank.TopRotation())) - PlayerTank.Object3D::RotationX() * sin(ToRad(PlayerTank.TopRotation())))" + "ToDeg(atan2(PlayerTank.AimDirectionY(), PlayerTank.AimDirectionX()))" ] }, { "type": { - "value": "SetAngle" + "value": "Scene3D::Base3DBehavior::SetRotationY" }, "parameters": [ "Bullet", + "Object3D", "=", - "PlayerTank.TopRotation() + PlayerTank.Angle()" + "-ToDeg(asin(clamp(PlayerTank.AimDirectionZ(), -1, 1)))" ] }, { @@ -3058,15 +3058,14 @@ }, { "type": { - "value": "Physics3D::Physics3DBehavior::ApplyImpulseTowardPosition" + "value": "Physics3D::Physics3DBehavior::ApplyImpulseAtCenter" }, "parameters": [ "Bullet", "Physics3D", - "15", - "Bullet.X() + XFromAngleAndDistance(PlayerTank.Angle() + PlayerTank.TopRotation(), 20)", - "Bullet.Y() + YFromAngleAndDistance(PlayerTank.Angle() + PlayerTank.TopRotation(), 20)", - "Bullet.Object3D::Z() + sin(ToRad(-1 * Bullet.Object3D::RotationY())) * 10" + "15 * PlayerTank.AimDirectionX()", + "15 * PlayerTank.AimDirectionY()", + "15 * PlayerTank.AimDirectionZ()" ] }, { @@ -3198,7 +3197,7 @@ "conditions": [ { "type": { - "value": "Distance" + "value": "Distance3D" }, "parameters": [ "Target", @@ -3216,7 +3215,7 @@ "parameters": [ "Target", "Physics3D", - "-5 * (300 - (Target.Distance(Bullet)))", + "-5 * (300 - Target.Object3D::Distance3D(Bullet))", "Bullet.X() + XFromAngleAndDistance(Target.AngleToObject(Bullet), 500)", "Bullet.Y() + YFromAngleAndDistance(Target.AngleToObject(Bullet), 500)", "0" @@ -3664,13 +3663,7 @@ "authorIds": [], "dependencies": [], "globalVariables": [], - "sceneVariables": [ - { - "name": "CannonWidth", - "type": "number", - "value": 0 - } - ], + "sceneVariables": [], "eventsFunctions": [], "eventsFunctionsFolderStructure": { "folderName": "__ROOT" @@ -3990,10 +3983,10 @@ "objectGroups": [] }, { - "description": "Return the distance between the end of the cannon and the center of the TankTop object", - "fullName": "Return CannonWidth", + "description": "Return the X position of the end of the cannon, in the scene.", + "fullName": "Muzzle position (X)", "functionType": "Expression", - "name": "CannonWidth", + "name": "MuzzleX", "sentence": "", "events": [ { @@ -4002,19 +3995,185 @@ "actions": [ { "type": { - "value": "TankConfiguration::TankTop::CannonInfo" + "value": "SetReturnNumber" }, "parameters": [ - "TankTop_Combined", - "" + "Object.ToParentX(TankTop_Combined.MuzzleX(), TankTop_Combined.MuzzleY(), TankTop_Combined.MuzzleZ())" ] - }, + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::CombinedTank", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the Y position of the end of the cannon, in the scene.", + "fullName": "Muzzle position (Y)", + "functionType": "Expression", + "name": "MuzzleY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentY(TankTop_Combined.MuzzleX(), TankTop_Combined.MuzzleY(), TankTop_Combined.MuzzleZ())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::CombinedTank", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the Z position of the end of the cannon, in the scene.", + "fullName": "Muzzle position (Z)", + "functionType": "Expression", + "name": "MuzzleZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ { "type": { "value": "SetReturnNumber" }, "parameters": [ - "CannonWidth" + "Object.ToParentZ(TankTop_Combined.MuzzleX(), TankTop_Combined.MuzzleY(), TankTop_Combined.MuzzleZ())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::CombinedTank", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the X of the direction the cannon points at (a unit vector), in the scene.", + "fullName": "Aim direction (X)", + "functionType": "Expression", + "name": "AimDirectionX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentDirectionX(TankTop_Combined.AimDirectionX(), TankTop_Combined.AimDirectionY(), TankTop_Combined.AimDirectionZ())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::CombinedTank", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the Y of the direction the cannon points at (a unit vector), in the scene.", + "fullName": "Aim direction (Y)", + "functionType": "Expression", + "name": "AimDirectionY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentDirectionY(TankTop_Combined.AimDirectionX(), TankTop_Combined.AimDirectionY(), TankTop_Combined.AimDirectionZ())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::CombinedTank", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the Z of the direction the cannon points at (a unit vector), in the scene.", + "fullName": "Aim direction (Z)", + "functionType": "Expression", + "name": "AimDirectionZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentDirectionZ(TankTop_Combined.AimDirectionX(), TankTop_Combined.AimDirectionY(), TankTop_Combined.AimDirectionZ())" ] } ] @@ -4055,7 +4214,22 @@ ] }, { - "functionName": "CannonWidth" + "functionName": "MuzzleX" + }, + { + "functionName": "MuzzleY" + }, + { + "functionName": "MuzzleZ" + }, + { + "functionName": "AimDirectionX" + }, + { + "functionName": "AimDirectionY" + }, + { + "functionName": "AimDirectionZ" } ] }, @@ -4290,11 +4464,11 @@ "objectGroups": [] }, { - "description": "Record variables related to the TankCannon object", - "fullName": "Record TankCannon information", - "functionType": "Action", - "name": "CannonInfo", - "sentence": "Record information for the TankCannon of _PARAM0_", + "description": "Return the X position of the end of the cannon, in the tank containing the tank top.", + "fullName": "Muzzle position (X)", + "functionType": "Expression", + "name": "MuzzleX", + "sentence": "", "events": [ { "type": "BuiltinCommonInstructions::Standard", @@ -4302,17 +4476,193 @@ "actions": [ { "type": { - "value": "SetNumberVariable" + "value": "SetReturnNumber" }, "parameters": [ - "CannonWidth", - "=", - "TankCanon.Width() + TankTop.Width()/2" + "Object.ToParentX(TankCanon.X() + TankCanon.Object3D::ForwardX() * TankCanon.Width(), TankCanon.Y() + TankCanon.Object3D::ForwardY() * TankCanon.Width(), TankCanon.Object3D::Z() + TankCanon.Object3D::ForwardZ() * TankCanon.Width())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::TankTop", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the Y position of the end of the cannon, in the tank containing the tank top.", + "fullName": "Muzzle position (Y)", + "functionType": "Expression", + "name": "MuzzleY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentY(TankCanon.X() + TankCanon.Object3D::ForwardX() * TankCanon.Width(), TankCanon.Y() + TankCanon.Object3D::ForwardY() * TankCanon.Width(), TankCanon.Object3D::Z() + TankCanon.Object3D::ForwardZ() * TankCanon.Width())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::TankTop", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the Z position of the end of the cannon, in the tank containing the tank top.", + "fullName": "Muzzle position (Z)", + "functionType": "Expression", + "name": "MuzzleZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentZ(TankCanon.X() + TankCanon.Object3D::ForwardX() * TankCanon.Width(), TankCanon.Y() + TankCanon.Object3D::ForwardY() * TankCanon.Width(), TankCanon.Object3D::Z() + TankCanon.Object3D::ForwardZ() * TankCanon.Width())" ] } ] } ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::TankTop", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the X of the direction the cannon points at (a unit vector), in the tank containing the tank top.", + "fullName": "Aim direction (X)", + "functionType": "Expression", + "name": "AimDirectionX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentDirectionX(TankCanon.Object3D::ForwardX(), TankCanon.Object3D::ForwardY(), TankCanon.Object3D::ForwardZ())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::TankTop", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the Y of the direction the cannon points at (a unit vector), in the tank containing the tank top.", + "fullName": "Aim direction (Y)", + "functionType": "Expression", + "name": "AimDirectionY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentDirectionY(TankCanon.Object3D::ForwardX(), TankCanon.Object3D::ForwardY(), TankCanon.Object3D::ForwardZ())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "TankConfiguration::TankTop", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Return the Z of the direction the cannon points at (a unit vector), in the tank containing the tank top.", + "fullName": "Aim direction (Z)", + "functionType": "Expression", + "name": "AimDirectionZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Object.ToParentDirectionZ(TankCanon.Object3D::ForwardX(), TankCanon.Object3D::ForwardY(), TankCanon.Object3D::ForwardZ())" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, "parameters": [ { "description": "Object", @@ -4331,7 +4681,22 @@ "functionName": "Elevation" }, { - "functionName": "CannonInfo" + "functionName": "MuzzleX" + }, + { + "functionName": "MuzzleY" + }, + { + "functionName": "MuzzleZ" + }, + { + "functionName": "AimDirectionX" + }, + { + "functionName": "AimDirectionY" + }, + { + "functionName": "AimDirectionZ" } ] }, diff --git a/scripts/lib/ExampleGDevelopVersion.js b/scripts/lib/ExampleGDevelopVersion.js index 0135c923f..fe7c2c60c 100644 --- a/scripts/lib/ExampleGDevelopVersion.js +++ b/scripts/lib/ExampleGDevelopVersion.js @@ -8,16 +8,48 @@ const gdevelopVersionsByInstructionType = { // The "Body type" action of the 3D physics. 'Physics3D::Physics3DBehavior::SetBodyType': '>=5.6.285', + // The conditions comparing objects in 3D. + Distance3D: '>=5.6.286', + IsTurnedTowardObject3D: '>=5.6.286', }; +/** + * The expressions, written in the parameters of the actions and conditions, + * that need a GDevelop more recent than the one needed by the extensions used + * by an example. + * @type {Array<{expressionPattern: RegExp, gdevelopVersion: string}>} + */ +const gdevelopVersionsByExpression = [ + { + // The conversions of a custom object to and from the space containing it, + // used by the events of the custom object. + expressionPattern: + /\bObject\.(?:To|From)Parent(?:X|Y|Z|Angle|DirectionX|DirectionY|DirectionZ)\(/, + gdevelopVersion: '>=5.6.286', + }, + { + // The distances in 3D. + expressionPattern: + /::Distance3D\(|::DistanceToPosition3D\(|\bDistanceBetweenPositions3D\(/, + gdevelopVersion: '>=5.6.286', + }, +]; + /** * @param {*} value A part of a project, as read from its file. * @param {Set} instructionTypes Filled with the types of the actions * and conditions found in it. + * @param {Set} instructionParameters Filled with the parameters of + * these actions and conditions. */ -const collectInstructionTypes = (value, instructionTypes) => { +const collectInstructions = ( + value, + instructionTypes, + instructionParameters +) => { if (Array.isArray(value)) { - for (const item of value) collectInstructionTypes(item, instructionTypes); + for (const item of value) + collectInstructions(item, instructionTypes, instructionParameters); return; } if (!value || typeof value !== 'object') return; @@ -27,9 +59,35 @@ const collectInstructionTypes = (value, instructionTypes) => { Array.isArray(value.parameters) ) { instructionTypes.add(value.type.value); + for (const parameter of value.parameters) { + if (typeof parameter === 'string') instructionParameters.add(parameter); + } } for (const key in value) - collectInstructionTypes(value[key], instructionTypes); + collectInstructions(value[key], instructionTypes, instructionParameters); +}; + +/** + * @param {string} gdevelopVersion Like ">=5.6.285". + * @returns {Array} + */ +const getVersionNumbers = (gdevelopVersion) => + gdevelopVersion.replace('>=', '').split('.').map(Number); + +/** + * @param {string} gdevelopVersion Like ">=5.6.286". + * @param {string} otherGDevelopVersion Like ">=5.6.285". + * @returns {boolean} + */ +const isMoreRecentThan = (gdevelopVersion, otherGDevelopVersion) => { + const versionNumbers = getVersionNumbers(gdevelopVersion); + const otherVersionNumbers = getVersionNumbers(otherGDevelopVersion); + for (let index = 0; index < versionNumbers.length; index++) { + const difference = + (versionNumbers[index] || 0) - (otherVersionNumbers[index] || 0); + if (difference !== 0) return difference > 0; + } + return false; }; /** @@ -43,13 +101,33 @@ const collectInstructionTypes = (value, instructionTypes) => { const getExampleGDevelopVersion = (projectObject, usedExtensionNames) => { /** @type {Set} */ const instructionTypes = new Set(); - collectInstructionTypes(projectObject, instructionTypes); - for (const instructionType in gdevelopVersionsByInstructionType) { - if (instructionTypes.has(instructionType)) { - return gdevelopVersionsByInstructionType[instructionType]; - } - } - return usedExtensionNames.includes('Physics3D') ? '>=5.5.220' : ''; + /** @type {Set} */ + const instructionParameters = new Set(); + collectInstructions(projectObject, instructionTypes, instructionParameters); + + const neededGDevelopVersions = [ + ...Object.keys(gdevelopVersionsByInstructionType) + .filter((instructionType) => instructionTypes.has(instructionType)) + .map( + (instructionType) => gdevelopVersionsByInstructionType[instructionType] + ), + ...gdevelopVersionsByExpression + .filter(({ expressionPattern }) => + [...instructionParameters].some((parameter) => + expressionPattern.test(parameter) + ) + ) + .map(({ gdevelopVersion }) => gdevelopVersion), + ...(usedExtensionNames.includes('Physics3D') ? ['>=5.5.220'] : []), + ]; + return neededGDevelopVersions.reduce( + (mostRecentGDevelopVersion, gdevelopVersion) => + !mostRecentGDevelopVersion || + isMoreRecentThan(gdevelopVersion, mostRecentGDevelopVersion) + ? gdevelopVersion + : mostRecentGDevelopVersion, + '' + ); }; module.exports = { getExampleGDevelopVersion }; diff --git a/scripts/lib/__tests__/ExampleGDevelopVersion.spec.js b/scripts/lib/__tests__/ExampleGDevelopVersion.spec.js index cd601e3c7..c283f8bfc 100644 --- a/scripts/lib/__tests__/ExampleGDevelopVersion.spec.js +++ b/scripts/lib/__tests__/ExampleGDevelopVersion.spec.js @@ -22,11 +22,12 @@ const createFakeEvent = (actions, subEvents = []) => ({ }); /** - * @param {{ sceneEvents?: Array<*>, extensionFunctionEvents?: Array<*> }} events + * @param {{ sceneEvents?: Array<*>, extensionFunctionEvents?: Array<*>, customObjectFunctionEvents?: Array<*> }} events */ const createFakeProjectObject = ({ sceneEvents = [], extensionFunctionEvents = [], + customObjectFunctionEvents = [], }) => ({ layouts: [{ name: 'Game Scene', objects: [], events: sceneEvents }], externalEvents: [], @@ -36,6 +37,14 @@ const createFakeProjectObject = ({ eventsFunctions: [ { name: 'MyFunction', events: extensionFunctionEvents }, ], + eventsBasedObjects: [ + { + name: 'MyTank', + eventsFunctions: [ + { name: 'MuzzleX', events: customObjectFunctionEvents }, + ], + }, + ], }, ], }); @@ -48,6 +57,9 @@ const applyImpulseAction = createFakeInstruction( 'Physics3D::Physics3DBehavior::ApplyImpulse', ['Enemy', 'Physics3D', '0', '0', '0'] ); +const returnMuzzleXAction = createFakeInstruction('SetReturnNumber', [ + 'Object.ToParentX(Cannon.X() + Cannon.Width(), Cannon.Y(), Cannon.Object3D::Z())', +]); describe('getExampleGDevelopVersion', () => { it('needs a GDevelop with the "Body type" action when a sub-event of a scene uses it', () => { @@ -82,6 +94,68 @@ describe('getExampleGDevelopVersion', () => { ); }); + it('needs a GDevelop with the conversions of custom objects when a custom object uses them', () => { + const projectObject = createFakeProjectObject({ + customObjectFunctionEvents: [createFakeEvent([returnMuzzleXAction])], + }); + + expect(getExampleGDevelopVersion(projectObject, [])).toBe('>=5.6.286'); + }); + + it('needs a GDevelop with the 3D distances when a condition or an expression uses them', () => { + const conditionProjectObject = createFakeProjectObject({ + sceneEvents: [ + { + ...createFakeEvent([]), + conditions: [ + createFakeInstruction('Distance3D', ['Player', 'Key', '120', '']), + ], + }, + ], + }); + const expressionProjectObject = createFakeProjectObject({ + sceneEvents: [ + createFakeEvent([ + createFakeInstruction('SetNumberVariable', [ + 'Range', + '=', + 'Player.Object3D::Distance3D(Key)', + ]), + ]), + ], + }); + + expect(getExampleGDevelopVersion(conditionProjectObject, [])).toBe( + '>=5.6.286' + ); + expect(getExampleGDevelopVersion(expressionProjectObject, [])).toBe( + '>=5.6.286' + ); + }); + + it('needs the most recent GDevelop of all the features used', () => { + const projectObject = createFakeProjectObject({ + sceneEvents: [createFakeEvent([setBodyTypeAction])], + customObjectFunctionEvents: [createFakeEvent([returnMuzzleXAction])], + }); + + expect(getExampleGDevelopVersion(projectObject, ['Physics3D'])).toBe( + '>=5.6.286' + ); + }); + + it('does not take a function of another object named like a conversion for one', () => { + const projectObject = createFakeProjectObject({ + sceneEvents: [ + createFakeEvent([ + createFakeInstruction('SetX', ['Bullet', '=', 'Ship.ToParentX()']), + ]), + ], + }); + + expect(getExampleGDevelopVersion(projectObject, [])).toBe(''); + }); + it('accepts any GDevelop for the other examples', () => { const projectObject = createFakeProjectObject({});