private void SpawnVessel(VesselData vesselData, List <ProtoCrewMember> crewData = null) { string gameDataDir = KSPUtil.ApplicationRootPath; Debug.Log("Spawning a vessel named '" + vesselData.name + "'"); // Set additional info for landed vessels bool landed = false; if (!vesselData.orbiting) { landed = true; if (vesselData.altitude == null || vesselData.altitude < 0) { vesselData.altitude = 35;//LocationUtil.TerrainHeight(vesselData.latitude, vesselData.longitude, vesselData.body); } //Vector3d pos = vesselData.body.GetWorldSurfacePosition(vesselData.latitude, vesselData.longitude, vesselData.altitude.Value); Vector3d pos = vesselData.body.GetRelSurfacePosition(vesselData.latitude, vesselData.longitude, vesselData.altitude.Value); vesselData.orbit = new Orbit(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, vesselData.body); vesselData.orbit.UpdateFromStateVectors(pos, vesselData.body.getRFrmVel(pos), vesselData.body, Planetarium.GetUniversalTime()); } else { vesselData.orbit.referenceBody = vesselData.body; } ConfigNode[] partNodes; //UntrackedObjectClass sizeClass; ShipConstruct shipConstruct = null; bool hasClamp = false; float lcHeight = 0; ConfigNode craftNode; Quaternion craftRotation = Quaternion.identity; if (!string.IsNullOrEmpty(vesselData.craftURL)) { // Save the current ShipConstruction ship, otherwise the player will see the spawned ship next time they enter the VAB! ConfigNode currentShip = ShipConstruction.ShipConfig; shipConstruct = ShipConstruction.LoadShip(vesselData.craftURL); if (shipConstruct == null) { Debug.Log("ShipConstruct was null when tried to load '" + vesselData.craftURL + "' (usually this means the file could not be found)."); return;//continue; } craftNode = ConfigNode.Load(vesselData.craftURL); lcHeight = ConfigNode.ParseVector3(craftNode.GetNode("PART").GetValue("pos")).y; craftRotation = ConfigNode.ParseQuaternion(craftNode.GetNode("PART").GetValue("rot")); // Restore ShipConstruction ship ShipConstruction.ShipConfig = currentShip; // Set the name if (string.IsNullOrEmpty(vesselData.name)) { vesselData.name = shipConstruct.shipName; } // Set some parameters that need to be at the part level uint missionID = (uint)Guid.NewGuid().GetHashCode(); uint launchID = HighLogic.CurrentGame.launchID++; foreach (Part p in shipConstruct.parts) { p.flightID = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); p.missionID = missionID; p.launchID = launchID; p.flagURL = vesselData.flagURL ?? HighLogic.CurrentGame.flagURL; // Had some issues with this being set to -1 for some ships - can't figure out // why. End result is the vessel exploding, so let's just set it to a positive // value. p.temperature = 1.0; } //add minimal crew //bool success = false; Part part = shipConstruct.parts.Find(p => p.protoModuleCrew.Count < p.CrewCapacity); // Add the crew member if (part != null && VesselMoverToolbar.addCrewMembers) { if (VesselMoverToolbar.selectCrewMembers) { ProtoCrewMember crewMember = crewData.FirstOrDefault(); if (crewMember != null) { part.AddCrewmemberAt(crewMember, part.protoModuleCrew.Count); } VesselMoverToolbar.SelectedCrewMembers.Clear(); } else { // Create the ProtoCrewMember ProtoCrewMember crewMember = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(); crewMember.gender = UnityEngine.Random.Range(0, 100) > 50 ? ProtoCrewMember.Gender.Female : ProtoCrewMember.Gender.Male; //crewMember.trait = "Pilot"; // Add them to the part part.AddCrewmemberAt(crewMember, part.protoModuleCrew.Count); } } // Create a dummy ProtoVessel, we will use this to dump the parts to a config node. // We can't use the config nodes from the .craft file, because they are in a // slightly different format than those required for a ProtoVessel (seriously // Squad?!?). ConfigNode empty = new ConfigNode(); ProtoVessel dummyProto = new ProtoVessel(empty, null); Vessel dummyVessel = new Vessel(); dummyVessel.parts = shipConstruct.Parts; dummyProto.vesselRef = dummyVessel; // Create the ProtoPartSnapshot objects and then initialize them foreach (Part p in shipConstruct.parts) { dummyVessel.loaded = false; p.vessel = dummyVessel; dummyProto.protoPartSnapshots.Add(new ProtoPartSnapshot(p, dummyProto, true)); } foreach (ProtoPartSnapshot p in dummyProto.protoPartSnapshots) { p.storePartRefs(); } // Create the ship's parts List <ConfigNode> partNodesL = new List <ConfigNode>(); foreach (ProtoPartSnapshot snapShot in dummyProto.protoPartSnapshots) { ConfigNode node = new ConfigNode("PART"); snapShot.Save(node); partNodesL.Add(node); } partNodes = partNodesL.ToArray(); // Estimate an object class, numbers are based on the in game description of the // size classes. //float size = shipConstruct.shipSize.magnitude / 2.0f; //if (size < 4.0f) //{ // sizeClass = UntrackedObjectClass.A; //} //else if (size < 7.0f) //{ // sizeClass = UntrackedObjectClass.B; //} //else if (size < 12.0f) //{ // sizeClass = UntrackedObjectClass.C; //} //else if (size < 18.0f) //{ // sizeClass = UntrackedObjectClass.D; //} //else //{ // sizeClass = UntrackedObjectClass.E; //} } else { // Create crew member array ProtoCrewMember[] crewArray = new ProtoCrewMember[vesselData.crew.Count]; int i = 0; foreach (CrewData cd in vesselData.crew) { // Create the ProtoCrewMember ProtoCrewMember crewMember = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(ProtoCrewMember.KerbalType.Crew); if (cd.name != null) { crewMember.KerbalRef.name = cd.name; } crewArray[i++] = crewMember; } // Create part nodes uint flightId = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); partNodes = new ConfigNode[1]; partNodes[0] = ProtoVessel.CreatePartNode(vesselData.craftPart.name, flightId, crewArray); // Default the size class //sizeClass = UntrackedObjectClass.A; // Set the name if (string.IsNullOrEmpty(vesselData.name)) { vesselData.name = vesselData.craftPart.name; } } // Create additional nodes ConfigNode[] additionalNodes = new ConfigNode[0]; //DiscoveryLevels discoveryLevel = vesselData.owned ? DiscoveryLevels.Owned : DiscoveryLevels.Unowned; //additionalNodes[0] = ProtoVessel.CreateDiscoveryNode(discoveryLevel, sizeClass, contract.TimeDeadline, contract.TimeDeadline); // Create the config node representation of the ProtoVessel ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(vesselData.name, vesselData.vesselType, vesselData.orbit, 0, partNodes, additionalNodes); // Additional seetings for a landed vessel if (!vesselData.orbiting) { Vector3d norm = vesselData.body.GetRelSurfaceNVector(vesselData.latitude, vesselData.longitude); double terrainHeight = 0.0; if (vesselData.body.pqsController != null) { terrainHeight = vesselData.body.pqsController.GetSurfaceHeight(norm) - vesselData.body.pqsController.radius; } bool splashed = false;// = landed && terrainHeight < 0.001; // Create the config node representation of the ProtoVessel // Note - flying is experimental, and so far doesn't work protoVesselNode.SetValue("sit", (splashed ? Vessel.Situations.SPLASHED : landed ? Vessel.Situations.LANDED : Vessel.Situations.FLYING).ToString()); protoVesselNode.SetValue("landed", (landed && !splashed).ToString()); protoVesselNode.SetValue("splashed", splashed.ToString()); protoVesselNode.SetValue("lat", vesselData.latitude.ToString()); protoVesselNode.SetValue("lon", vesselData.longitude.ToString()); protoVesselNode.SetValue("alt", vesselData.altitude.ToString()); protoVesselNode.SetValue("landedAt", vesselData.body.name); // Figure out the additional height to subtract float lowest = float.MaxValue; if (shipConstruct != null) { foreach (Part p in shipConstruct.parts) { foreach (Collider collider in p.GetComponentsInChildren <Collider>()) { if (collider.gameObject.layer != 21 && collider.enabled) { lowest = Mathf.Min(lowest, collider.bounds.min.y); } } } } else { foreach (Collider collider in vesselData.craftPart.partPrefab.GetComponentsInChildren <Collider>()) { if (collider.gameObject.layer != 21 && collider.enabled) { lowest = Mathf.Min(lowest, collider.bounds.min.y); } } } if (lowest == float.MaxValue) { lowest = 0; } // Figure out the surface height and rotation Quaternion normal = Quaternion.LookRotation((Vector3)norm);// new Vector3((float)norm.x, (float)norm.y, (float)norm.z)); Quaternion rotation = Quaternion.identity; float heading = vesselData.heading; if (shipConstruct == null) { rotation = rotation * Quaternion.FromToRotation(Vector3.up, Vector3.back); } else if (shipConstruct.shipFacility == EditorFacility.SPH) { rotation = rotation * Quaternion.FromToRotation(Vector3.forward, -Vector3.forward); heading += 180.0f; } else { rotation = rotation * Quaternion.FromToRotation(Vector3.up, Vector3.forward); rotation = Quaternion.FromToRotation(Vector3.up, -Vector3.up) * rotation; //rotation = craftRotation; vesselData.heading = 0; vesselData.pitch = 0; } rotation = rotation * Quaternion.AngleAxis(heading, Vector3.back); rotation = rotation * Quaternion.AngleAxis(vesselData.roll, Vector3.down); rotation = rotation * Quaternion.AngleAxis(vesselData.pitch, Vector3.left); // Set the height and rotation if (landed || splashed) { float hgt = (shipConstruct != null ? shipConstruct.parts[0] : vesselData.craftPart.partPrefab).localRoot.attPos0.y - lowest; hgt += vesselData.height; foreach (Part p in shipConstruct.Parts) { LaunchClamp lc = p.FindModuleImplementing <LaunchClamp>(); if (lc) { hasClamp = true; break; } } if (!hasClamp) { hgt += 35; } else { hgt += lcHeight; } protoVesselNode.SetValue("hgt", hgt.ToString(), true); } protoVesselNode.SetValue("rot", KSPUtil.WriteQuaternion(normal * rotation), true); // Set the normal vector relative to the surface Vector3 nrm = (rotation * Vector3.forward); protoVesselNode.SetValue("nrm", nrm.x + "," + nrm.y + "," + nrm.z, true); protoVesselNode.SetValue("prst", false.ToString(), true); } // Add vessel to the game ProtoVessel protoVessel = HighLogic.CurrentGame.AddVessel(protoVesselNode); //protoVessel.vesselRef.transform.rotation = protoVessel.rotation; // Store the id for later use vesselData.id = protoVessel.vesselRef.id; //protoVessel.vesselRef.currentStage = 0; StartCoroutine(PlaceSpawnedVessel(protoVessel.vesselRef, !hasClamp)); // Associate it so that it can be used in contract parameters //ContractVesselTracker.Instance.AssociateVessel(vesselData.name, protoVessel.vesselRef); //destroy prefabs foreach (Part p in FindObjectsOfType <Part>()) { if (!p.vessel) { Destroy(p.gameObject); } } }
public void Update() { Vessel vessel = FlightGlobals.ActiveVessel; // easier to use vessel // safety check if (vessel == null || !HighLogic.LoadedSceneIsFlight) { return; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // atmospheric shake // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // up the shake based on atmopshereic density and surface speed float spdDensity = (float)(vessel.atmDensity) * (float)FlightGlobals.ship_srfSpeed; // limit here, mainly for space planes spdDensity = Mathf.Clamp(spdDensity, 0, maxSpdDensityEarly); // exagerate shake if semideployed, dampen if deployed foreach (Part part in vessel.Parts) { foreach (PartModule module in part.Modules) { if (module.moduleName.Contains("ModuleParachute")) { ModuleParachute p = module as ModuleParachute; if (p.deploymentState == ModuleParachute.deploymentStates.SEMIDEPLOYED && !vessel.LandedOrSplashed) { spdDensity *= 1.25f; } if (p.deploymentState == ModuleParachute.deploymentStates.DEPLOYED && !vessel.LandedOrSplashed) { spdDensity *= 0.75f; } } // RealChute Support, reworked to be compatible with RealChute v1.2 if (module.moduleName.Contains("RealChuteModule")) { PartModule p = part.Modules["RealChuteModule"]; Type pType = p.GetType(); object parachutes = pType.GetField("parachutes").GetValue(p); foreach (object parachute in (parachutes as IEnumerable)) { Type cType = parachute.GetType(); if (cType.GetField("depState").GetValue(parachute) == "PREDEPLOYED") { spdDensity *= 1.25f; } if ((cType.GetField("depState").GetValue(parachute) == "DEPLOYED") || (cType.GetField("depState").GetValue(parachute) == "LOWDEPLOYED")) { spdDensity *= 0.75f; } } } } } // lifted from DRE (thanks r4m0n), gets the mach / reentry fx if (afx == null) { GameObject fx = GameObject.Find("FXLogic"); if (fx != null) { afx = fx.GetComponent <AerodynamicsFX>(); } } // sirhaxington special: use weird values I found to determine if mach or reentry, there has to be a better way... if ((afx != null) && (afx.FxScalar > 0.01)) { // hack, whatever the .b color value is, always is this for re-entry, .11 something if (afx.fxLight.color.b < 0.12f) { burnDownTime = atmoBurnDownTimes[0]; } // hack, whatever the .b color value is, always is this for mach fx, .21 something if (afx.fxLight.color.b > 0.20f) { // since we * 10, only do this if it's going to increase... if (afx.FxScalar > 0.1) { spdDensity *= (afx.FxScalar * 10); } } } // ease back into normal atmophere from re-entry if (burnDownTime > 0) { spdDensity *= (afx.FxScalar * burnDownTime * 1000); burnDownTime -= Time.deltaTime; } // dont go too crazy... spdDensity = Mathf.Clamp(spdDensity, 0, maxSpdDensity); if (!vessel.isEVA) { shakeAmt = ReturnLargerAmt((UnityEngine.Random.insideUnitSphere * spdDensity) / 500000, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, (UnityEngine.Random.Range(-0.1f, 0.1f) * spdDensity) / 5000), shakeRot); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // parachute open shake // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int chuteCheck = 0; // re-do this every frame, check against previous frame to see if chute opened // a chute has popped... // Note: Don't need to do this with realChutes as they tend to open slow anyway foreach (Part part in vessel.parts) { foreach (PartModule module in part.Modules) { if (module.moduleName.Contains("ModuleParachute")) { ModuleParachute p = module as ModuleParachute; if (p.deploymentState != ModuleParachute.deploymentStates.DEPLOYED) { chuteCheck++; } } } } // check against previous frames' chutes, then prep shake event if (chuteCheck < totalUndeployedChutes) { doParaFull = true; paraShakeTime = paraShakeTimes[0]; } // set this at end of check for next frame totalUndeployedChutes = chuteCheck; // do the parachute pop shake if (paraShakeTime > 0 && doParaFull) { shakeAmt = ReturnLargerAmt(UnityEngine.Random.insideUnitSphere / 500, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, UnityEngine.Random.Range(-0.5f, 0.5f)), shakeRot); paraShakeTime -= Time.deltaTime; } else if (paraShakeTime <= 0) { doParaFull = false; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // decoupler shakes // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // total is grabbed from event handler if (ejectionForceTotal > 0) { // playing around with set shake timers, not sure if I like this way but it works for now if (ejectionForceTotal <= 15) { decoupleShakeTime = decoupleShakeTimes[0]; } else if (ejectionForceTotal <= 250) { decoupleShakeTime = decoupleShakeTimes[1]; } else if (ejectionForceTotal <= 500) { decoupleShakeTime = decoupleShakeTimes[2]; } else if (ejectionForceTotal <= 1000) { decoupleShakeTime = decoupleShakeTimes[3]; } else { decoupleShakeTime = decoupleShakeTimes[4]; } decoupleShakeForce = ejectionForceTotal; doDecoupleShake = true; ejectionForceTotal = 0; } // do the decoupler shake if (decoupleShakeTime > 0 && doDecoupleShake) { shakeAmt = ReturnLargerAmt(UnityEngine.Random.insideUnitSphere * decoupleShakeForce / 500000, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, UnityEngine.Random.Range(-0.5f, 0.5f)), shakeRot); decoupleShakeTime -= Time.deltaTime; } else if (decoupleShakeTime <= 0) { doDecoupleShake = false; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // docking shakes // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // do the dock shake...we set the time from the handler, no need for other checks if (dockShakeTime > 0) { shakeAmt = ReturnLargerAmt(UnityEngine.Random.insideUnitSphere / 1000, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, UnityEngine.Random.Range(-0.07f, 0.07f)), shakeRot); dockShakeTime -= Time.deltaTime; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // launch clamp shakes // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int clampCheck = 0; // a clamp has detached... foreach (Part part in vessel.parts) { foreach (PartModule module in part.Modules) { if (module.moduleName.Contains("LaunchClamp")) { LaunchClamp lc = module as LaunchClamp; if (lc.enabled) { clampCheck++; } } } } // check against previous frames' chutes, then prep shake event if (clampCheck < totalClampedClamps) { doClamp = true; clampShakeTime = clampShakeTimes[0]; } // set this at end of check for next frame totalClampedClamps = clampCheck; // do the parachute pop shake if (clampShakeTime > 0 && doClamp) { shakeAmt = ReturnLargerAmt(UnityEngine.Random.insideUnitSphere / 500, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, UnityEngine.Random.Range(-0.7f, 0.7f)), shakeRot); clampShakeTime -= Time.deltaTime; } else if (clampShakeTime <= 0) { doClamp = false; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // engine shakes // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // check both engine types (rapier uses ModuleEnginesFX, most use ModuleEngines) then base shake on thrust amount foreach (Part part in vessel.Parts) { foreach (PartModule module in part.Modules) { if (module.moduleName.Contains("ModuleEnginesFX")) { ModuleEnginesFX e = module as ModuleEnginesFX; if (e.isOperational) { float solidScalar = 1.0f; // scale up SRBs if (e.propellants.Count > 0) { foreach (Propellant p in e.propellants) { if (p.name == "SolidFuel") { solidScalar = 2.5f; } } } engineThrustTotal += (e.finalThrust * solidScalar); } if (engineThrustTotal > 0) { doEngineShake = true; } } else if (module.moduleName.Contains("ModuleEngines")) { ModuleEngines e = module as ModuleEngines; if (e.isOperational) { float typeScalar = 1.0f; // scale up SRBs, down jets if (e.propellants.Count > 0) { foreach (Propellant p in e.propellants) { if (p.name == "SolidFuel") { typeScalar = 2.5f; } else if (p.name == "IntakeAir") { typeScalar = 0.01f; } } } engineThrustTotal += (e.finalThrust * typeScalar); } if (engineThrustTotal > 0) { doEngineShake = true; } } // don't go too crazy... engineThrustTotal = Mathf.Clamp(engineThrustTotal, 0, maxEngineForce); } } // do engine shake... if (engineThrustTotal > 0 && doEngineShake) { shakeAmt = ReturnLargerAmt((UnityEngine.Random.insideUnitSphere * (engineThrustTotal / 1000)) / 800, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, UnityEngine.Random.Range(-0.8f, 0.8f) * (engineThrustTotal / 1000)), shakeRot); } else if (engineThrustTotal <= 0) { doEngineShake = false; } // reset every frame engineThrustTotal = 0; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // nearby collision shakes // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // do the collision shake...we set the time from the handler, no need for other checks if (collisionShakeTime > 0) { shakeAmt = ReturnLargerAmt(UnityEngine.Random.insideUnitSphere / 50, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, UnityEngine.Random.Range(-1.5f, 1.5f)), shakeRot); collisionShakeTime -= Time.deltaTime; } // reset for next frame, use negative since we're looking for distance now collisionClosest = -1; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // rover ground shakes // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float spdRover = (float)FlightGlobals.ship_srfSpeed; doRover = false; float roverScalar = 1.0f; foreach (Part part in vessel.Parts) { foreach (PartModule module in part.Modules) { if (module.moduleName.Contains("ModuleWheel")) { if (part.GroundContact) { if (vessel.landedAt.Length == 0 || vessel.landedAt.ToString() == "KSC") { roverScalar = 2.0f; } // maybe later, do biome specific shakes //CBAttributeMap currentBiome = vessel.mainBody.BiomeMap; //print(currentBiome.GetAtt(vessel.latitude * Mathf.Deg2Rad, vessel.longitude * Mathf.Deg2Rad).name); //print(currentBiome.ToString()); doRover = true; } } if (module.moduleName.Contains("ModuleLandingGear")) { if (part.Landed) { if (vessel.landedAt.Length == 0 || vessel.landedAt.ToString() == "KSC") // basically, in and around KSC { roverScalar = 2.0f; } doRover = true; } } } } spdRover *= roverScalar; // dont go too crazy... spdRover = Mathf.Clamp(spdRover, 0, maxSpdRover); if (doRover && !vessel.isEVA) { shakeAmt = ReturnLargerAmt((UnityEngine.Random.insideUnitSphere * spdRover) / 50000, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, (UnityEngine.Random.Range(-0.1f, 0.1f) * spdRover) / 500), shakeRot); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // landing shakes // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // note, parts that break off may throw this off int landedCurParts = 0; foreach (Part part in vessel.Parts) { if (part.GroundContact || part.WaterContact) { landedCurParts++; } } // if more parts are touching the ground this frame... if (landedCurParts > landedPrevParts) { doLanded = true; // do I need horizontal surface speed as well? hmmm... landedShakeForce = landedPrevSrfSpd; if (landedShakeForce <= 0.5) { landedShakeTime = landedShakeTimes[0]; } else if (landedShakeForce <= 1.5) { landedShakeTime = landedShakeTimes[1]; } else if (landedShakeForce <= 3.0) { landedShakeTime = landedShakeTimes[2]; } else if (landedShakeForce <= 5.0) { landedShakeTime = landedShakeTimes[3]; } else { landedShakeTime = landedShakeTimes[4]; } if (doRover) { landedShakeForce /= 2; } landedShakeForce = Mathf.Clamp(landedShakeForce, 0, maxLandedForce); } // set the current parts for the next frame landedPrevParts = landedCurParts; // do the landing / touching ground / water shake if (doLanded && !vessel.isEVA) { if (landedShakeTime > 0) { shakeAmt = ReturnLargerAmt((UnityEngine.Random.insideUnitSphere * landedShakeForce) / 3600, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, UnityEngine.Random.Range(-0.1f, 0.1f) * landedShakeForce), shakeRot); landedShakeTime -= Time.deltaTime; } else { doLanded = false; } } // set the speed for the next frame landedPrevSrfSpd = (float)FlightGlobals.ActiveVessel.srfSpeed; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // EVA Shakes (under construction) // // to do: polish shakes (check on a few planets), rotation add back in // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (vessel.isEVA) { KerbalEVA eva = (KerbalEVA)vessel.rootPart.Modules["KerbalEVA"]; // if an anim has changed if (eva.fsm.currentStateName != evaAnimState) { //print(evaSrfSpedPrev); if (eva.fsm.currentStateName == "Landing") // standard landing from a jump / RCS { evaShakeTime = evaShakeTimes[2]; evaAnimShakeAmount = (int)(45000 / evaSrfSpedPrev); } else if (eva.fsm.currentStateName == "Ragdoll") // we landed too hard / jumped and landed at an odd angle { evaShakeTime = evaShakeTimes[5]; evaAnimShakeAmount = (int)(8000 / evaSrfSpedPrev); } else if (eva.fsm.currentStateName == "Low G Bound (Grounded - FPS)") // each step on a low g world should be felt { evaShakeTime = evaShakeTimes[2]; evaAnimShakeAmount = (int)(50000); } else if (eva.fsm.currentStateName == "Ladder (Acquire)") // feel the grab a bit more { evaShakeTime = evaShakeTimes[5]; evaAnimShakeAmount = (int)(1000000); } evaAnimState = eva.fsm.currentStateName; //print(evaAnimState); } else if (evaAnimState == "Ragdoll" && vessel.Landed && evaShakeTime <= 0) // when ragging and sliding along the surface, keep shaking { evaShakeTime = evaShakeTimes[5]; evaAnimShakeAmount = (int)(8000 / evaSrfSpedPrev); } else if (evaAnimState == "Ladder (Acquire)" && evaShakeTime >= 0) // when ragging and sliding along the surface or falling, update shaking { if (evaShakeTime < 0.3) { evaAnimShakeAmount = (int)(4000); } } // update shake based on timers if (evaShakeTime > 0) { shakeAmt = ReturnLargerAmt(UnityEngine.Random.insideUnitSphere / evaAnimShakeAmount, shakeAmt); evaShakeTime -= Time.deltaTime; } // RCS Cam Shake if (Math.Round(eva.Fuel, 3) != Math.Round(evaFuel, 3)) { evaFuel = eva.Fuel; shakeAmt = ReturnLargerAmt(UnityEngine.Random.insideUnitSphere / evaRCSShakeAmount, shakeAmt); Math.Round(eva.Fuel, 3); } // grab frame two behind to test against evaSrfSpedPrev = evaSrfSped; evaSrfSped = (float)vessel.srfSpeed; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // DO THE HARLEMSHAKE! o/\o // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Set isCrewed to true if not unmanned, used to remove shake in control room when using ProbeControlRoom mod bool isCrewed = false; foreach (Part part in vessel.Parts) { if (part.protoModuleCrew.Count >= 1) { isCrewed = true; } } // hopefully we've picked the largest values... also, don't shake while paused, looks dumb if (InternalCamera.Instance != null) { if (!gamePaused && InternalCamera.Instance.isActive && isCrewed) // isCrewed for shake only if not in control room { InternalCamera.Instance.camera.transform.localPosition = shakeAmt; InternalCamera.Instance.camera.transform.localRotation *= shakeRot; } } // for a different first person EVA mod... bool FPEVAMod = false; foreach (Part part in vessel.Parts) { foreach (PartModule module in part.Modules) { if (module.moduleName.Contains("EVACamera")) { FPEVAMod = true; } } } // rotation is wonky in EVA, skip if (vessel.isEVA && FlightCamera.fetch.minDistance == 0.01f && FlightCamera.fetch.maxDistance == 0.01f) { if (shakeAmt.x != 0 && shakeAmt.y != 0 && shakeAmt.z != 0) { FlightCamera.fetch.transform.localPosition += shakeAmt; } } else if (vessel.isEVA && FPEVAMod) { FlightCamera.fetch.transform.localPosition += (shakeAmt * 1000); } // reset the shake vals every frame and start over... shakeAmt = new Vector3(0.0f, 0.0f, 0.0f); shakeRot = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f); }