public void LowBattery(ZACommons commons, EventDriver eventDriver, bool started) { // Enable/disable reactor according to state ZACommons.EnableBlocks(ZACommons.GetBlocksOfType <IMyReactor>(commons.Blocks), started); }
public void UndockDisable(ZACommons commons, EventDriver eventDriver) { ZACommons.EnableBlocks(ZACommons.GetBlocksOfType <IMyShipConnector>(commons.Blocks, connector => connector.DefinitionDisplayNameText == "Connector"), false); }
public void ManageShip(ZACommons commons, EventDriver eventDriver, bool docked) { if (!docked) { for (var i = 0; i < DockingHandlers.Length; i++) { DockingHandlers[i].DockingAction(commons, eventDriver, false); } } ZACommons.EnableBlocks(ZACommons.GetBlocksOfType <IMyThrust>(commons.Blocks), !docked); ZACommons.EnableBlocks(ZACommons.GetBlocksOfType <IMyGyro>(commons.Blocks), !docked); var batteries = ZACommons.GetBlocksOfType <IMyBatteryBlock>(commons.Blocks); foreach (var battery in batteries) { battery.OnlyRecharge = docked; battery.OnlyDischarge = !docked; } if (!docked) { ZACommons.EnableBlocks(ZACommons.GetBlocksOfType <IMyReactor>(commons.Blocks), true); } if (TOUCH_ANTENNA) { ZACommons.EnableBlocks(ZACommons.GetBlocksOfType <IMyRadioAntenna>(commons.Blocks), !docked); // Now defaults to off in 01.124. Thanks, Keen! if (!docked) { eventDriver.Schedule(2, (c, ed) => { ZACommons.GetBlocksOfType <IMyRadioAntenna>(commons.Blocks).ForEach(antenna => antenna.SetValue <bool>("EnableBroadCast", true)); }); } } if (TOUCH_LANTENNA) { ZACommons.EnableBlocks(ZACommons.GetBlocksOfType <IMyLaserAntenna>(commons.Blocks), !docked); } if (TOUCH_BEACON) { ZACommons.EnableBlocks(ZACommons.GetBlocksOfType <IMyBeacon>(commons.Blocks), !docked); } if (TOUCH_LIGHTS) { ZACommons.EnableBlocks(ZACommons.GetBlocksOfType <IMyLightingBlock>(commons.Blocks), !docked); } // Disable tools if we just docked if (TOUCH_TOOLS && docked) { ZACommons.EnableBlocks(ZACommons.GetBlocksOfType <IMyShipToolBase>(commons.Blocks), false); } if (TOUCH_OXYGEN) { ZACommons.EnableBlocks(ZACommons.GetBlocksOfType <IMyGasGenerator>(commons.Blocks), !docked); ZACommons.EnableBlocks(ZACommons.GetBlocksOfType <IMyOxygenFarm>(commons.Blocks), !docked); ZACommons.EnableBlocks(ZACommons.GetBlocksOfType <IMyAirVent>(commons.Blocks, vent => ((IMyAirVent)vent).Depressurize && vent.CustomName.IndexOf("[Intake]", ZACommons.IGNORE_CASE) >= 0), !docked); var tanks = ZACommons.GetBlocksOfType <IMyGasTank>(commons.Blocks, tank => tank.CustomName.IndexOf("[Excluded]", ZACommons.IGNORE_CASE) < 0); tanks.ForEach(tank => tank.Stockpile = docked); } if (TOUCH_SENSORS) { ZACommons.EnableBlocks(ZACommons.GetBlocksOfType <IMySensorBlock>(commons.Blocks), !docked); } if (docked) { for (var i = 0; i < DockingHandlers.Length; i++) { DockingHandlers[i].DockingAction(commons, eventDriver, true); } } IsDocked = docked; if (IsDocked) { eventDriver.Schedule(RunDelay, Sleep); } }
private static List <IMyBatteryBlock> GetBatteries(ZACommons commons) { return(ZACommons.GetBlocksOfType <IMyBatteryBlock>(commons.Blocks, battery => battery.IsFunctional && battery.CustomName.IndexOf("[Excluded]", ZACommons.IGNORE_CASE) < 0)); }
public void HandleCommand(ZACommons commons, EventDriver eventDriver, string argument, Action preUndock = null) { argument = argument.Trim().ToLower(); if (argument == "smartundock") { if (preUndock != null) { preUndock(); } // First, determine which connector we were connected through IMyShipConnector connected = null; var connectors = ZACommons.GetBlocksOfType <IMyShipConnector>(commons.Blocks, connector => connector.DefinitionDisplayNameText == "Connector"); // Avoid Ejectors for (var e = connectors.GetEnumerator(); e.MoveNext();) { var connector = (IMyShipConnector)e.Current; if (connector.IsLocked && connector.IsConnected) { // Assume the first one as well connected = connector; break; } } UndockTarget = null; UndockBackward = null; if (connected != null) { // Undock in the forward direction of the *other* connector var other = connected.OtherConnector; var forward = other.Orientation.TransformDirection(Base6Directions.Direction.Forward); var forwardPoint = other.CubeGrid.GridIntegerToWorld(other.Position + Base6Directions.GetIntVector(forward)); var forwardVector = Vector3D.Normalize(forwardPoint - other.GetPosition()); // Determine target undock point var shipControl = (ShipControlCommons)commons; UndockTarget = shipControl.ReferencePoint + SMART_UNDOCK_DISTANCE * forwardVector; // And original orientation UndockForward = shipControl.ReferenceForward; UndockUp = shipControl.ReferenceUp; // Schedule the autopilot UndockBackward = connected.Orientation.TransformDirection(Base6Directions.Direction.Backward); BeginUndock(commons, eventDriver); Mode = UNDOCKING; SaveMode(commons); } SaveUndockTarget(commons); // Next, physically undock for (var e = connectors.GetEnumerator(); e.MoveNext();) { var connector = (IMyShipConnector)e.Current; if (connector.IsLocked) { connector.ApplyAction("Unlock"); } } ZACommons.EnableBlocks(connectors, false); // Unlock landing gears as well var gears = ZACommons.GetBlocksOfType <IMyLandingGear>(commons.Blocks); gears.ForEach(block => { var gear = (IMyLandingGear)block; if (gear.IsLocked) { gear.ApplyAction("Unlock"); } }); // Disable connectors 1 second from now eventDriver.Schedule(1.0, (c, ed) => { ZACommons.EnableBlocks(ZACommons.GetBlocksOfType <IMyShipConnector>(c.Blocks, connector => connector.DefinitionDisplayNameText == "Connector"), false); // Avoid Ejectors }); } else if (argument == "rtb") { // No target, no RTB if (UndockTarget == null) { return; } // Schedule the autopilot BeginReturn(commons, eventDriver); Mode = RETURNING; SaveMode(commons); } else if (argument == "smartreset") { autopilot.Reset(commons); ResetMode(commons); } }
public void SafeMode(ZACommons commons, EventDriver eventDriver) { var shipControl = (ShipControlCommons)commons; // Ensure dampeners are enabled (again, possibly) ZACommons.GetBlocksOfType <IMyShipController>(commons.Blocks).ForEach(block => { var controller = (IMyShipController)block; block.SetValue <bool>("DampenersOverride", true); }); // Make sure we have working thrusters in all directions // Statically initialized arrays are a bit iffy in-game, so we // do this the hard way if (HaveWorkingThrusters(shipControl, Base6Directions.Direction.Forward) && HaveWorkingThrusters(shipControl, Base6Directions.Direction.Backward) && HaveWorkingThrusters(shipControl, Base6Directions.Direction.Left) && HaveWorkingThrusters(shipControl, Base6Directions.Direction.Right) && HaveWorkingThrusters(shipControl, Base6Directions.Direction.Up) && HaveWorkingThrusters(shipControl, Base6Directions.Direction.Down)) { // All looks well return; } // Check again after a second eventDriver.Schedule(1.0, (c, ed) => { var sc = (ShipControlCommons)c; var forward = HaveWorkingThrusters2(sc, Base6Directions.Direction.Forward); var backward = HaveWorkingThrusters2(sc, Base6Directions.Direction.Backward); var up = HaveWorkingThrusters2(sc, Base6Directions.Direction.Up); var left = HaveWorkingThrusters2(sc, Base6Directions.Direction.Left); var right = HaveWorkingThrusters2(sc, Base6Directions.Direction.Right); var down = HaveWorkingThrusters2(sc, Base6Directions.Direction.Down); if (forward && backward && up && left && right && down) { // All is well return; } // Otherwise, pick a working direction and pass off to // ReverseThrust Base6Directions.Direction direction; if (forward) { direction = Base6Directions.Direction.Forward; } else if (backward) { direction = Base6Directions.Direction.Backward; } else if (up) { direction = Base6Directions.Direction.Up; } else if (left) { direction = Base6Directions.Direction.Left; } else if (right) { direction = Base6Directions.Direction.Right; } else if (down) { direction = Base6Directions.Direction.Down; } else { // Ha ha. No working thrusters at all. return; } new ReverseThrust().Init(c, ed, EMERGENCY_STOP_MAX_GYRO_ERROR, thrusterDirection: direction); }); }
private static List <IMyReactor> GetAllReactors(ZACommons commons) { return(ZACommons.GetBlocksOfType <IMyReactor>(commons.AllBlocks, reactor => reactor.IsFunctional && reactor.CustomName.IndexOf("[Excluded]", ZACommons.IGNORE_CASE) < 0)); }
private List <IMyBatteryBlock> GetBatteries(ZACommons commons) { return(ZACommons.GetBlocksOfType <IMyBatteryBlock>(commons.Blocks, battery => battery.IsFunctional && battery.Enabled)); }
private void HandleCommandInternal(string argument) { var parts = argument.Split(new char[] { ' ' }, 2); if (parts.Length != 2) { return; } var command = parts[0]; argument = parts[1].Trim(); if (command == "inner" || command == "space" || command == "toggle") { ZACommons.BlockGroup room; if (roomsMap.TryGetValue(argument, out room)) { var vents = ToVents(ZACommons.GetBlocksOfType <IMyAirVent>(room.Blocks)); var current = GetAirlockState(vents); int target = AIRLOCK_STATE_UNKNOWN; switch (command) { case "space": target = AIRLOCK_STATE_VACUUM; break; case "inner": target = AIRLOCK_STATE_PRESSURIZED; break; case "toggle": target = current == AIRLOCK_STATE_PRESSURIZED ? AIRLOCK_STATE_VACUUM : AIRLOCK_STATE_PRESSURIZED; break; } ChangeRoomState(room.Name, vents, ToDoors(ZACommons.GetBlocksOfType <IMyDoor>(room.Blocks)), current, target, null); } } else if (command == "open") { // Find named group ZACommons.BlockGroup group; if (doorVentGroups.TryGetValue(argument, out group)) { var doors = ToDoors(ZACommons.GetBlocksOfType <IMyDoor>(group.Blocks)); // Only need to do one (assumes door groups were set up correctly... heh) if (doors.Count > 0) { var door = doors[0]; ZACommons.BlockGroup room; if (doorVentRooms.TryGetValue(door, out room)) { var otherVents = ToVents(ZACommons.GetBlocksOfType <IMyAirVent>(group.Blocks)); var roomVents = ToVents(ZACommons.GetBlocksOfType <IMyAirVent>(room.Blocks)); var target = GetAirlockState(otherVents); var current = GetAirlockState(roomVents); ChangeRoomState(room.Name, roomVents, ToDoors(ZACommons.GetBlocksOfType <IMyDoor>(room.Blocks)), current, target, doors); } } } } }
public void Run(ZACommons commons) { // Only care about power producers on this ship var producers = ZACommons.GetBlocksOfType <IMyTerminalBlock>(commons.Blocks, block => block is IMyPowerProducer); // Limit to functional batteries var batteries = ZACommons.GetBlocksOfType <IMyBatteryBlock>(producers, battery => battery.IsFunctional); if (batteries.Count == 0) { return; // Nothing to do if no batteries to manage } // All other power producers var otherProducers = ZACommons.GetBlocksOfType <IMyTerminalBlock>(producers, block => !(block is IMyBatteryBlock)); var batteryDetails = GetPowerDetails <IMyBatteryBlock>(batteries); var otherDetails = GetPowerDetails <IMyTerminalBlock>(otherProducers); var totalDetails = batteryDetails + otherDetails; //commons.Echo("Battery Load: " + batteryDetails.ToString()); //commons.Echo("Other Load: " + otherDetails.ToString()); //commons.Echo("Total Load: " + totalDetails.ToString()); // First, the degenerate cases... if (totalDetails.MaxPowerOutput == 0.0f) { return; // Don't think this is possible... } if (otherDetails.MaxPowerOutput == 0.0f) { // Nothing but our batteries. Just put all batteries online. ZACommons.EnableBlocks(batteries, true); ZACommons.SetBatteryRecharge(batteries, false); return; } var totalLoad = totalDetails.CurrentPowerOutput / totalDetails.MaxPowerOutput; // If total system load exceeds threshold, attempt to bring a battery online. if (totalLoad > POWER_MANAGER_HIGH_LOAD_THRESHOLD) { QuietTimer = TimeSpan.FromSeconds(0); // Sort by stored power descending batteries.Sort(batteryComparerDesc); // Bring the first recharging battery online, shut down all other recharging batteries // (just shutting them down would probably free up a lot of power... need // separate case?) var found = false; for (var e = batteries.GetEnumerator(); e.MoveNext();) { var battery = e.Current; if (battery.Enabled && battery.ProductionEnabled) { continue; // Battery is already online, don't touch it } if (!found) { // Found the first one, bring it online if (!battery.Enabled) { battery.GetActionWithName("OnOff_On").Apply(battery); } ZACommons.SetBatteryRecharge(battery, false); found = true; } else { // Shut it down if (battery.Enabled) { battery.GetActionWithName("OnOff_Off").Apply(battery); } } } } else if (totalLoad < POWER_MANAGER_LOW_LOAD_THRESHOLD) { QuietTimer += commons.Program.ElapsedTime; if (QuietTimer >= QuietTimeout) { // NB We don't reset QuietTimer, so we will trigger at next tick again // (assuming load is still low) // Sort from low to high batteries.Sort(batteryComparer); // Any batteries actively discharging? if (batteryDetails.CurrentPowerOutput > 0.0f) { // Take a battery offline, starting with the least charged. // Note, we cannot actually start recharging until they are all offline DisableOneBattery(batteries, totalDetails); } else { // All batteries are down, enable one for charging // (repeat next tick until we break low threshold, in which case QuietTimer // will reset) // But first, check if it would put us over the threshold var first = batteries[0]; // Assume all the same var wouldBeOutput = otherDetails.CurrentPowerOutput + first.DefinedPowerOutput; // Assume MaxPowerOutput = MaxPowerInput (not available to us) //commons.Echo("Would-be Output: " + ZACommons.FormatPower(wouldBeOutput)); var wouldBeLoad = wouldBeOutput / otherDetails.MaxPowerOutput; //commons.Echo("Would-be Load: " + wouldBeLoad); if (wouldBeLoad <= POWER_MANAGER_HIGH_LOAD_THRESHOLD) { RechargeOneBattery(batteries); } } } } else { QuietTimer = TimeSpan.FromSeconds(0); } }
private IMyMotorStator GetRotor(ZACommons.BlockGroup group) { var rotors = ZACommons.GetBlocksOfType <IMyMotorStator>(group.Blocks); return(rotors.Count == 1 ? rotors[0] : null); }
public void Run(ZACommons commons, EventDriver eventDriver) { var tanks = ZACommons.GetBlocksOfType <IMyOxygenTank>(commons.AllBlocks, tank => tank.IsFunctional && tank.IsWorking && tank.CustomName.IndexOf("[Excluded]", ZACommons.IGNORE_CASE) < 0); var currentState = GetOxygenState(tanks); // Only act on level transitions if (PreviousState != currentState) { PreviousState = currentState; // We need a tri-state variable, so... nullable bool?generateOxygen = null; bool?farmOxygen = null; switch (currentState) { case OXYGEN_LEVEL_HIGH: // Turn off all oxygen production generateOxygen = false; farmOxygen = false; break; case OXYGEN_LEVEL_NORMAL: // Do nothing (but keep farms up) farmOxygen = true; break; case OXYGEN_LEVEL_BUFFER: // Start producing oxygen generateOxygen = true; farmOxygen = true; break; case OXYGEN_LEVEL_LOW: // Definitely start producing oxygen generateOxygen = true; farmOxygen = true; // For now, it's intentional that we start timer blocks // on all grids... we'll see how it goes ZACommons.StartTimerBlockWithName(commons.AllBlocks, LOW_OXYGEN_NAME); break; } if (generateOxygen != null) { // Limit to this grid -- don't mess with any other ship's systems var generators = ZACommons.GetBlocksOfType <IMyOxygenGenerator>(commons.Blocks, block => block.IsFunctional); ZACommons.EnableBlocks(generators, (bool)generateOxygen); } if (farmOxygen != null) { var farms = ZACommons.GetBlocksOfType <IMyOxygenFarm>(commons.Blocks, block => block.IsFunctional); // Farms don't implement IMyFunctionalBlock?? ZACommons.EnableBlocks(farms, (bool)farmOxygen); // We'll count atmosphere intake vents too, since they're "free" var vents = ZACommons.GetBlocksOfType <IMyAirVent>(commons.Blocks, vent => vent.IsFunctional && ((IMyAirVent)vent).IsDepressurizing && vent.CustomName.IndexOf("[Intake]", ZACommons.IGNORE_CASE) >= 0); ZACommons.EnableBlocks(vents, (bool)farmOxygen); } } eventDriver.Schedule(RunDelay, Run); }