Scripting:STNE SRS
From STNE Wiki
Getting short range sensor data
The CMyShip has a method to retrieve data on ships in the current sector. It's accessed through the SRS method of CMyShip. Each object is a ship in the sector, whether or nor it's yours. Because the object is based on a list, you can easily retrieve the number of ships in the sector by using the Count property of the list.
// Assume your probe and another probe is in the sector, this would return 2 Var Ship As CMyShip = new CMyShip(123456); WriteLine (Ship.SRS.Count); // output the number of ships in the sector
Recently, LRSShipSlots was added. As of the time of this writing, it returns SRS slots count of the sector.
// Assume your probe and another probe is in the sector, this would return 1.0 Var Ship As CMyShip = new CMyShip(123456); WriteLine (Ship.LRSShipSlots); // output the slot count of the ships in the sector
If you wanted to filter out your ships, you would need to iterate through the list of ships in SRS and not add them to an accumulator. This is accomplished by checking the CMyShip.UserID against your userid. The caveat is, it won't capture copiloted ships, that needs to be handled differently.
Var Uid As Integer = 67890; // your uid Var Sid As Integer = 123456; // the ship to use for SRS data Var ShipCount As Integer = 0; Var ShipSlots As Double = 0.0; Var StringSlots As String; // used to run time convert slots to a string formatting Var SRSShip As CShip; // Note, this is a CShip, not a CMyShip Var Message As CStringBuilder = New CStringBuilder(); // Avoid ineffecient string concatenations of '&' Var Ship As CMyShip = New CMyShip(Sid); Var iter As IEnumerator = Ship.SRS.GetEnumerator; // don't store SRS, just get the iterator directly While (iter.MoveNext) { SRSShip = iter.Current; // cast back to a CShip object If (SRSShip.UserID <> Uid) { // This does not work for copiloted ships, just your own ShipCount = ShipCount + 1; ShipSlots = ShipSlots + SRSShip.Definition.Slots; } } StringSlots = ShipSlots; Message.Append("Number of ships is "); Message.Append(ShipCount); Message.Append(", for "); Message.Append(StringSlots.Replace(",", "."); Message.Append(" slots."); WriteLine (Message.ToString);
Assuming the same two probes are in the sector, the output would be “Number of ships is 1, for .5 slots.” As I stated above, this code would only show ships that were not owned by you. In order to filter out copiloted ships as well, you need to go one step further and make a list of all the ships you have control of. Luckily there's an iterator you can use to build a list of ship IDs that you control.
// Function to create and return a CIntegerList of ships under your control Function MyShipList() As CIntegerList { Var List As CIntegerList = New CIntegerList(); Var Ship As CMyShip; Var iter As CShipEnumerator = New CShipEnumerator(); While (iter.Next()) { Ship = iter.CurrentShip; List.Add(Ship.ShipID); } Return List; } Var Sid As Integer = 123456; // the ship to use the SRS data from Var ShipCount As Integer = 0; Var ShipSlots As Double = 0.0; Var StringSlots As String; Var SRSShip As CShip; // Note, this is a CShip, not a CMyShip Var Message As CStringBuilder = New CStringBuilder(); // Avoid ineffecient string concatenations of '&' Var Ship As CMyShip = New CMyShip(Sid); Var Ships As CIntegerList = MyShipList(); // retrieve the ship list (nccs only) Var iter As IEnumerator = Ship.SRS.GetEnumerator; // get the iterator directly again While (iter.MoveNext) { SRSShip = iter.Current; // recast to a CShip // use the list builtin method to check if a value exists within the list If (NOT Ships.Contains(SRSShip.ShipID)) { ShipCount = ShipCount + 1; ShipSlots = ShipSlots + SRSShip.Definition.Slots; } } StringSlots = ShipSlots; Message.Append("Number of ships is "); Message.Append(ShipCount); Message.Append(", for "); Message.Append(StringSlots.Replace(",", "."); Message.Append(" slots."); WriteLine (Message.ToString);
Note the addition of the MyShipList function. It iterates though the CShipEnumerator, which contains all the ships under your control, and adds them to a list that can then be cross referenced. The rest of the code, except for the owner check, is the same as before.
Keep in mind your colonies also have the SRS object, so it could be applied to your colonies just as easily. It's a matter of changing The variable Ship from CMyShip to CMyColony. Of course you should also change the variable names to reflect that the object is a colony not a ship.
Function MyShipList() As CIntegerList { Var List As CIntegerList = New CIntegerList(); Var Ship As CMyShip; Var iter As CShipEnumerator = New CShipEnumerator(); While (iter.Next()) { Ship = iter.CurrentShip; List.Add(Ship.ShipID); } Return List; } Var Cid As Integer = 01234; // Was Sid Var ShipCount As Integer = 0; Var ShipSlots As Double = 0.0; Var StringSlots As String; Var SRSShip As CShip; // Note, this is a CShip, not a CMyShip Var Message As CStringBuilder = New CStringBuilder(); // Avoid ineffecient string concatenations of '&' Var Colony As CMyColony = New CMyColony(Cid); // Was Ship Var Ships As CIntegerList = MyShipList(); Var iter As IEnumerator = Colony.SRS.GetEnumerator; While (iter.MoveNext) { SRSShip = iter.Current; If (NOT Ships.Contains(SRSShip.ShipID)) { ShipCount = ShipCount + 1; ShipSlots = ShipSlots + SRSShip.Definition.Slots; } } StringSlots = ShipSlots; Message.Append("Number of ships is "); Message.Append(ShipCount); Message.Append(", for "); Message.Append(StringSlots.Replace(",", "."); Message.Append(" slots."); WriteLine (Message.ToString);
By now you're ready to wrap your code into a class. For the most part, it should be accessed statically. You'll want to alter the function that filters in order to allow for either a ship or a colony. If you move the loops for SRS into its own method, and use functions for ship and colony that just handle the differences between the two, this becomes a clean and fairly easy task
// Class to return the slots and count data as a single object, thereby requiring less specific functions Class SRSSummary { Var Slots As Double; Var Count As Integer; // I could have left this out,, it isn't used in the example. Included for completeness Function New (sid As Integer) { ; } // Create and initialize the class Function New (c As Integer, s As Double) { Slots = s; Count = c; } // Beans style Get/Set methods for data access Function GetShipSlots() As Double { Return Slots; } Function SetShipSlots(s As Double) { Slots = s; } Function GetShipCount() As Integer { Return Count; } Function SetShipCount(c As Integer) { Count = c; } } // The class that provides the desired data // Note the lack of a new function. Without it, this class is only accessible statically Class SRSData { // Make a CIntegerList of NCCs under your control Function MyShipList() As CIntegerList { Var List As CIntegerList = New CIntegerList(); Var Ship As CMyShip; Var iter As CShipEnumerator = New CShipEnumerator(); While (iter.Next()) { Ship = iter.CurrentShip; List.Add(Ship.ShipID); } Return List; } // Filter (CMyShip|CMyColony).SRS so only ships you don't control show up Function SRSSearch(srs As CShipList) As SRSSummary { Var shipcount As Integer = 0; Var shipslots As Double = 0.0; Var srsship As CShip; // Note, this is a CShip, not a CMyShip Var summary As SRSSummary; Var ships As CIntegerList = SRSData.MyShipList(); Var iter As IEnumerator = srs.GetEnumerator; While (iter.MoveNext) { srsship = iter.Current; If (NOT ships.Contains(srsship.ShipID)) { shipcount = shipcount + 1; shipslots = shipslots + srsship.Definition.Slots; } } Return New SRSSummary(shipcount, shipslots); } // I just can't bring myself to use a method named LRS to retrieve SRS data // Either the name will change to match the data, or the value will change to match the name. // This method returns the total of ships and slots within (CMyShip|CMyColony).SRS Function SRSAll(srs As CShipList) As SRSSummary { Var shipcount As Integer = 0; Var shipslots As Double = 0.0; Var srsship As CShip; // Note, this is a CShip, not a CMyShip Var summary As SRSSummary; Var iter As IEnumerator = srs.GetEnumerator; While (iter.MoveNext) { srsship = iter.Current; shipcount = shipcount + 1; shipslots = shipslots + srsship.Definition.Slots; } Return New SRSSummary(srs.Count, shipslots); } // Return the filtered version of SRS for a ship Function GetFilteredShipSRSSummary(shipID As Integer) As SRSSummary { Var ship As CMyShip = New CMyShip(shipID) Return SRSData.SRSSearch(Ship.SRS); } // Return the filtered version of SRS for a colony Function GetFilteredColonySRSSummary(colonyID As Integer) As SRSSummary { Var Colony As CMyColony = New CMyColony(colonyID); Return SRSData.SRSSearch(Colony.SRS); } // Return the total version of SRS for a ship Function GetShipSRSSummary(shipID As Integer) As SRSSummary { Var ship As CMyShip = New CMyShip(shipid); Return SRSData.SRSAll(Ship.SRS); } // Return the total version of SRS for a colony Function GetColonySRSSummary(colonyID As Integer) As SRSSummary { Var colony As CMyColony = New CMyColony(colonyID); Return SRSData.SRSAll(colony.SRS); } } // A fast output method. I could have done this within a table, but it adds unnecessary complexity for the example Function ReportSRS (name As String, filtered As SRSSummary, total As SRSSummary) { Var StringSlots As String; Var message as New CStringBuilder(); message.Append("SRS summary for "); message.Append(name); message.Append(": "); message.Append(filtered.GetShipCount()); message.Append ("/"); message.Append(total.GetShipCount()); message.Append(" ships for "); StringSlots = filtered.GetShipSlots(); message.Append(StringSlots.Replace(",", ".")); message.Append("/"); StringSlots = total.GetShipSlots(); message.Append(StringSlots.Replace(",", ".")); message.Append(" slots."); ScriptContext.WriteAppLog(message.ToString()); } // The Script Main() function. Function Main() { Var summarytotal As SRSSummary; // SRS total counts Var summaryother As SRSSummary; // SRS filtered counts Var shipid As Integer = 123456; // The ship ncc to use var colid As Integer = 01234; // The colony ID to use Var ship As New CmyShip(shipID); // call the create for the objects Var colony As New CmyColony(colid); // ship and colony summarytotal = SRSData.GetShipSRSSummary(shipid); // Get the totals for the ship summaryother = SRSData.GetFilteredShipSRSSummary(shipid); // and the filtered values ReportSRS(ship.Name, summaryother, summarytotal); // show the data summarytotal = SRSData.GetColonySRSSummary(colid); // Totals for the colony object summaryother = SRSData.GetFilteredColonySRSSummary(colid); // and the filtered values ReportSRS(colony.Name, summaryother, summarytotal); // Show them as well } // Call the main function Main();
As you can see from the code above, the SRS data from both the colonies and the ships are handled by the same method statically. This is true for both the filtered and non filtered version of the routine. Also, notice that rather than rewrite a function for each type of data, I just created a small class with beans style get/set methods to return the data. It adds a little more CPU and memory usage to do it this way, but the memory usage is easily offset by the code reuse. (you halved the amount of code by only writing 4 very minimal methods and 2 small methods instead of 4 small methods). Essentially you end up using a small amount of extra CPU for maintainable clean code. While this tutorial retrieves just the ship slots and count, from here it would be easy to extend the class to return any available data within a CShip object.
--Miltiades (En-1:56599) 06:07, 6 November 2011 (CET)