1. This forum is obsolete and read-only. Feel free to contact us at support.keenswh.com

Damage report script - I need some help improving please

Discussion in 'Programming (In-game)' started by spacedMatt, Jan 21, 2015.

Thread Status:
This last post in this thread was made more than 31 days old.
  1. spacedMatt

    spacedMatt Apprentice Engineer

    Messages:
    421
    This is my script for detecting damaged and missing blocks:
    Code:
    int blocksCount = 0;
    int workingBlocks = 0;
    string[] blockNames;
    void Main()
    {
        if(!initialized())    
        {
            speak("");
            blocksCount = getBlocksCount();
            setBlockNames();
            //speak("Initialized");
        }
        else
        {
            speak(missingBlockName()+" "+damagedBlockNames());
            blocksCount = getBlocksCount();
            workingBlocks = getWorkingBlocksCount();
        }
    }
    //-------------------------------------------------------------------------------------
    void speak(string text)     // set name of antenna[0] 
    {
        List<IMyTerminalBlock> antenna = new List<IMyTerminalBlock>{};
        GridTerminalSystem.GetBlocksOfType<IMyRadioAntenna>(antenna);
        
        antenna[0].SetCustomName(text);
    }
    //-------------------------------------------------------------------------------------
    bool initialized()     //if the antenna name is 'start' or 'restart' method = false; 
    {
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{};  
        GridTerminalSystem.GetBlocksOfType<IMyRadioAntenna>(blocks);  
      
        for( int i = 0 ; i < blocks.Count ; i++)  
            if(blocks[i].CustomName == "start" || blocks[i].CustomName == "restart") 
                        return false;        
            
        return true;
    }
    //------------------------------------------------------------------------------------
    int getBlocksCount()    //returns number of blocks on ship
    {     
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{}; 
        GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks);
        return blocks.Count;
    }
    int getWorkingBlocksCount()    //returns number of working blocks on the ship 
    {
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{};    
        GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks);    
          
        int index = 0;   
        for(int i = 0 ; i < blocks.Count ; i++)   
            if(blocks[i].IsWorking)   
                index++; 
        return index;
    }
    //------------------------------------------------------------------------------------
    void setBlockNames() // fills the blockNames array with the names of the blocks on the ship
    {
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{};
        GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks);
        
        blockNames = new string[blocks.Count];
        
        for( int i = 0 ; i < blocks.Count ; i++)
            blockNames[i] = blocks[i].CustomName;        
    }
    //------------------------------------------------------------------------------------
    string missingBlockName()    /* compaires the blockNames array (set when last run) with the
                                   current list of block names and returns the missing block name*/
    {
        string report = "Missing blocks: "; 
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{}; 
        GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks); 
         
        if(blockNames.Length > blocks.Count)
            for( int i = 0 ; i < blocks.Count; i++) 
                if(blockNames[i] != blocks[i].CustomName)
                     return report + blockNames[i]; 
        
        return "";        
    }
    string damagedBlockNames()    // returns string of damaged blocks
    {
        string report = "Damaged blocks: ";  
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{};  
        GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks);  
        
        int index = 0; 
        for(int i = 0 ; i < blocks.Count ; i++) 
            if(blocks[i].IsWorking) 
                index++;
        if(index < blocks.Count)
        {      
            for(int i = 0 ; i < blocks.Count ; i++) 
                if(!blocks[i].IsWorking) 
                    report = report+blocks[i].CustomName+", ";
            return report;  
        }
        else
            return "";
    } 
    //------------------------------------------------------------------------------------
    bool newBlockDamaged()    // detects when new block is damaged 
    {
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{};   
        GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks);   
         
        int index = 0;  
        for(int i = 0 ; i < blocks.Count ; i++)  
            if(blocks[i].IsWorking)  
                index++; 
        return index < workingBlocks;
    }
    bool newBlockLost()        // detects when new block is lost
    {
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{};    
        GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks);
        return blocks.Count < blocksCount;
    } 
    //------------------------------------------------------------------------------------
    // UNFINISHED
    void alarmBlockDamaged(){}
    void alarmBlockLost(){}
    
    
    First you name an antenna 'start',then when you run the script for the first time it will list all of the blocks, how many(int) and their names(string[]).

    When the script is run again it will look for missing or damaged blocks, printing the names along with weather it's lost or damaged:

    [​IMG] [​IMG] [​IMG]

    One of the problems is when I put any block back it removes the warning:

    [​IMG]

    I would like it to still give me a warning until I replace the block and rename it.

    Also I would like to keep the structure of the script, very minimal 'main' with simple methods below.

    Thanks.
     
    Last edited by a moderator: Jan 21, 2015
  2. DarrikVkir

    DarrikVkir Trainee Engineer

    Messages:
    80
    I'm about to head out, so I don't have the time to test it, but I believe that issue is caused by this line:

    if(blockNames.Length > blocks.Count)

    When you added the reactor, the blocks.count will equal the blocknames.length.
    Removing that line should prevent this issue, although it will make the script slightly more expensive as the script will iterate through the list every time it's run.

    Edit:

    Additionally, you'll want to change the for loop just below that if statement to make sure you don't exceed blockname's array... if you add a block after initializing without destroying a block, you'll exception out because blockname would be shorter than blocks.

    You can also make it cheaper to run by combining missingblocks and damagedblocks, so you only iterate through blocks once. There's a few things you'd need to change to do that, including changing the return so that it returns a string, which the for loop sets, after the for loop. You could also += the string to handle multiple missing and damaged blocks as well in that case.
     
    Last edited by a moderator: Jan 21, 2015
  3. spacedMatt

    spacedMatt Apprentice Engineer

    Messages:
    421
    Thanks I'll try this now and get back to you with my progress in a bit.
     
  4. spacedMatt

    spacedMatt Apprentice Engineer

    Messages:
    421
    Ok I've sorted it but any advice on how to make it better would be great.
    Damage Report (display through antenna version):
    Alarting you to damaged and missing blocks with the report displayed through an antenna.

    Code:
    /* To initialize set first antenna to 'antenna' then run with a timer.
        when a block is damaged or lost it will be displayed on the first antenna*/
    int blocksCount = 0;
    int workingBlocksCount = 0;
    string[] blockNames;
    void Main()
    {
        stopTimer();
        if(!initialized())    
        {
            blocksCount = getBlocksCount();
            blockNames = getBlockNames();
            workingBlocksCount = getWorkingBlocksCount();
            speak("");      
            triggerTimer();  
        }
        else
        {
           if(newBlockDamaged())
                alarmBlockDamaged();
                
           if(newBlockLost())
                alarmBlockLost();
           
            workingBlocksCount = getWorkingBlocksCount();
            blocksCount = getBlocksCount();   
            speak(missingBlockNames()+" "+damagedBlockNames());
            triggerTimer();
        }
    }
    //-----------------------------------------------------------------------------------------------
    void speak(string text)     // set name of antenna[0] 
    {
        List<IMyTerminalBlock> antenna = new List<IMyTerminalBlock>{};
        GridTerminalSystem.GetBlocksOfType<IMyRadioAntenna>(antenna);
        
        antenna[0].SetCustomName(text);
    }
    //-----------------------------------------------------------------------------------------------
    bool initialized()     //if the antenna name is 'antenna' method = false; 
    {
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{};  
        GridTerminalSystem.GetBlocksOfType<IMyRadioAntenna>(blocks);  
      
        for( int i = 0 ; i < blocks.Count ; i++)  
            if(blocks[i].CustomName == "antenna") 
                        return false;        
            
        return true;
    }
    //-----------------------------------------------------------------------------------------------
    int getBlocksCount()    //returns number of blocks on ship
    {     
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{}; 
        GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks);
        return blocks.Count;
    }
    int getWorkingBlocksCount()    //returns number of working blocks on the ship 
    {
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{};    
        GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks);    
          
        int index = 0;   
        for(int i = 0 ; i < blocks.Count ; i++)   
            if(blocks[i].IsWorking)   
                index++; 
        return index;
    }
    //-----------------------------------------------------------------------------------------------
    string[] getBlockNames() // returns array of block names
    {
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{};
        GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks);
           
        string[] names = new string[blocks.Count];
        
        for( int i = 0 ; i < blocks.Count ; i++)
            names[i] = blocks[i].CustomName;  
        
        return names;      
    }
    //-----------------------------------------------------------------------------------------------
    string missingBlockNames()    /* compaires the blockNames array (set when initialized) with the
                                                        current list of block names and returns the missing block name(s)*/
    {
        string report = ""; 
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{}; 
        GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks); 
        
        for( int i = 0 ; i < blockNames.Length; i++)
        {    
            bool noMatchFound = true;
            for(int j =0 ; j < blocks.Count; j++)
                if(blockNames[i] == blocks[j].CustomName || blockNames[i] == "antenna" && hasComms())
                {
                    noMatchFound = false;
                    break;
                }
            if(noMatchFound)
                   report = report + blockNames[i] + ", ";                           
        }
        if(report != "")
            return report = "Missing Blocks: " + report;
        else
            return report;    
    }
    string damagedBlockNames()    // returns string of damaged blocks
    {
        string report = "Damaged blocks: ";  
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{};  
        GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks);  
        
        int index = 0; 
        for(int i = 0 ; i < blocks.Count ; i++) 
            if(blocks[i].IsWorking) 
                index++;
        if(index < blocks.Count)
        {      
            for(int i = 0 ; i < blocks.Count ; i++) 
                if(!blocks[i].IsWorking) 
                    report = report+blocks[i].CustomName+", ";
            return report;  
        }
        else
            return "";
    } 
    //-----------------------------------------------------------------------------------------------
    bool newBlockDamaged()    // detects when new block is damaged 
    {
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{};   
        GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks);   
         
        int index = 0;  
        for(int i = 0 ; i < blocks.Count ; i++)  
            if(blocks[i].IsWorking)  
                index++; 
        return index < workingBlocksCount;
    }
    bool newBlockLost()        // detects when new block is lost
    {
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{};    
        GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks);
        return blocks.Count < blocksCount;
    } 
    //-----------------------------------------------------------------------------------------------
    bool hasComms()
    {
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{};    
        GridTerminalSystem.GetBlocksOfType<IMyRadioAntenna>(blocks);    
        return blocks.Count > 0;
    }
    //-----------------------------------------------------------------------------------------------
    void triggerTimer()
    {
        List<IMyTerminalBlock> timer = new List<IMyTerminalBlock>{};
        GridTerminalSystem.GetBlocksOfType<IMyTimerBlock>(timer);
        timer[0].GetActionWithName("TriggerNow").Apply(timer[0]);
    }
    void stopTimer()
    {
        List<IMyTerminalBlock> timer = new List<IMyTerminalBlock>{}; 
        GridTerminalSystem.GetBlocksOfType<IMyTimerBlock>(timer); 
        timer[0].GetActionWithName("Stop").Apply(timer[0]);
    }
    //-----------------------------------------------------------------------------------------------
    void alarmBlockDamaged()
    {     
        var soundBlock = GridTerminalSystem.GetBlockWithName("Sound Block (Damaged Block)") as IMySoundBlock;     
        soundBlock.GetActionWithName("PlaySound").Apply(soundBlock);
    }
    void alarmBlockLost()
    {
        var soundBlock = GridTerminalSystem.GetBlockWithName("Sound Block (Missing Block)") as IMySoundBlock;      
        soundBlock.GetActionWithName("PlaySound").Apply(soundBlock);    
    }
    
    I'm going to try and make it so you can choose weather you want to display from a beacon or antenna.

    Maybe add commands by naming the timer block for it to be read in the code, for things like resetting the blockNames array and clearing the display.
     
    Last edited by a moderator: Jan 22, 2015
  5. [POR]Shoterxx

    [POR]Shoterxx Apprentice Engineer

    Messages:
    103
    If you get the position of your block, then, trough your ship's IMyCubeGrid.GetCubeBlock(position), you're able to access that block's integrity, damage, build ratio, etc...

    https://steamcommunity.com/sharedfiles/filedetails/?id=368754412

    Check it, since I've done something similar.
     
  6. spacedMatt

    spacedMatt Apprentice Engineer

    Messages:
    421
    Thanks this was helpful:
    Code:
    List<IMyTerminalBlock> thrusters = new List<IMyTerminalBlock>();
    IMyTerminalBlock clock;
    void Main()   
    {   
        thrusters.Clear();   
        GridTerminalSystem.GetBlocksOfType<IMyThrust>(thrusters);    
        //Make sure the system clock is on!
        clock = GridTerminalSystem.GetBlockWithName("System Clock");
        clock.GetActionWithName("OnOff_On").Apply(clock);
        clock.GetActionWithName("TriggerNow").Apply(clock);                
       
        for(int i = 0; i < thrusters.Count; i++)  
        {
            var t_pos3i = thrusters[i].Position;
            var thruster = thrusters[i].CubeGrid.GetCubeBlock(t_pos3i);
            float cur_dmg = thruster.CurrentDamage;
            float total_dmg = thruster.MaxIntegrity;
            float integrity = (total_dmg-cur_dmg)/total_dmg;
            if (!thrusters[i].IsFunctional)
            {
                 thrusters[i].RequestShowOnHUD(true);
            }
            if (thrusters[i].IsFunctional)
            {
                thrusters[i].RequestShowOnHUD(false);
            }
            thrusters[i].SetCustomName("Engine ["+(integrity*100)+"%]");
            
        }
    }
    
    I hope you don't mind me showing your code, I just thought it would be useful for others.
     
  7. spacedMatt

    spacedMatt Apprentice Engineer

    Messages:
    421
    By doing it this way 'IMyCubeGrid' is it the only way to get current damage and max integrity?
     
  8. Phoera

    Phoera Senior Engineer

    Messages:
    1,713
    not Grid, SlimBlock, yes only, cuz SlimBlock is physical block, TerminalBlock is Functional of that block.

    here is sample
     
  9. DarrikVkir

    DarrikVkir Trainee Engineer

    Messages:
    80
    Just a suggestion:

    You can do the damaged block name function this way (it avoids going through the block list twice):

    Code:
    string damagedBlockNames()    // returns string of damaged blocks
    {
        string report = "Damaged blocks: ";  
        List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>{};  
        GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks);  
    
        int found = 0;    
        for(int i = 0 ; i < blocks.Count ; i++) 
            if(!blocks[i].IsWorking) 
           {
                report = report+blocks[i].CustomName+", ";
                found++;
           }
    
        if ( found > 0 ) 
          return report;
        
        return "";
    } 
    
     
Thread Status:
This last post in this thread was made more than 31 days old.