KontrolSystem2 icon indicating copy to clipboard operation
KontrolSystem2 copied to clipboard

looking for a way to wait until science experiements are ready

Open fbl100 opened this issue 2 years ago • 23 comments

I've searched through the docs and have yet to figure out how to determine when science experiments are available to run. Obviously the game knows this (the science icon flashes).

I'm hoping to write a script that will automatically start the experiments when the conditions have been met. This is probably not an issue in the code, per se, but in my inability to figure it out from the docs. Any help would be appreciated.

fbl100 avatar Feb 03 '24 20:02 fbl100

Hi, Not a solution, but some ideas :

With this ship : scienceShip (missing the Z-200 battery in the parts' pic) I would try this code :

use { CONSOLE } from ksp::console
use { Vessel, ModuleScienceExperiment } from ksp::vessel
use { wait_until, yield } from ksp::game
use { round } from core::math

/// Entry Point
pub fn main_flight(vessel: Vessel) -> Result<Unit, string> = {
    CONSOLE.clear()

    // https://kontrolsystem2.readthedocs.io/en/latest/reference/ksp/vessel.html#part
    const science_modules = vessel.parts
        .filter(fn(part) -> part.science_experiment.defined)
        .map(fn(part) -> part.science_experiment.value)

    // get parachutes
    const parachutes = vessel.parts
        .filter(fn(part) -> part.parachute.defined)
        .map(fn(part) -> part.parachute.value)

    // take off
    vessel.set_throttle(0.55)
    vessel.staging.next()
    wait_until(fn() -> vessel.staging.ready)

    // while going up
    while(round( vessel.up.dot(vessel.surface_velocity) ) >= 0) {
        if(vessel.engines.exists(fn(engine) -> engine.is_flameout)) { // drop engine
            vessel.staging.next()
            wait_until(fn() -> vessel.staging.ready)
        }

        // if their is experiences not running
        if(science_modules.exists(fn(science_module) -> !science_module.is_deployed))
            doScience(science_modules)

        yield() // let Unity do things
    }

    // arm parachutes
    for(parachute in parachutes)
        parachute.armed = true

    return Ok({})
}

fn doScience(science_modules: ModuleScienceExperiment[]) -> bool = {
    // https://kontrolsystem2.readthedocs.io/en/latest/reference/ksp/science.html
    for(science_module in science_modules) {
        return science_module.experiments
            .filter(fn(experiment) -> experiment.condition_met) // experience to do
            .map(fn(runnable_experiment) -> runnable_experiment.run_experiment()) // run experiment and get status being run
            .exists(fn(experiment_running) -> experiment_running) // search for at least one experiment being run
    }
    return false // no expriment to run have been found
}

Should give you a straight vertical flight until 80km apo, then let you fall safely on the ground. Enought to play with GSCM-01 and ASCM-A.

However, as I'm playing in sandbox mode, the science light never blink. I assume it's because researches are already acquired. It implies experiment.condition_met is always false, so experiments never run. You could also look at experiment.current_experiment_state == ExperimentState.READY and experiment.current_experiment_state != ExperimentState.ALREADYSTORED (dont forget to use { ExperimentState } from ksp::science) to launch your experiments, however, as experiment.condition_met, experiment.current_experiment_state is always true, at least in Sandbox mode. I bet this is not the case in campain mode.

Have fun :)

lefouvert avatar Feb 04 '24 14:02 lefouvert

The bindings to the science modules are still new, so I am still not entirely sure how everything behaves. The condition_met flag is taken directly from the internal data-structure of the game, maybe there is some update needed I am not aware of. In the meantime: Maybe you can check the current_experiment_state value of the experiment. I guess experiment.current_experiment_state == ExperimentState.READY means that it is ready to go?

untoldwind avatar Feb 05 '24 10:02 untoldwind

Thank you for the responses. I will give this a try.

fbl100 avatar Feb 05 '24 16:02 fbl100

I have been messing with this for a bit now and am becoming convinced that there's something missing that needs to be exposed. I've tried printing out all of the experiment variables and can't find anything that correlates to when the blue science light flashes.

My setup:

  • Brand new save w/ no science earned.
  • Simple rocket (pod + fuel tank + engine)
  • On the launch pad, I run my script. Crew Observations are performed (yay!)
  • Launch the rocket and monitor the console
  • No variables change, even though I'm now in the atmosphere and can click on the science button to do another crew observation

I was expecting/hoping that a variable on the crew observation would flip as soon as I got into the atmosphere.

Here's my script. The intent is just to run in a loop and execute science when available. Note that the 'can_run' function is just what I was using last. I've tried lots of combinations to no avail.

use { Vessel, ModuleScienceExperiment } from ksp::vessel
use { wait_until, yield } from ksp::game
use { round } from core::math
use { ExperimentState, Experiment, ResearchLocation } from ksp::science
use { format } from core::str

/// Entry Point
pub fn main_flight(vessel: Vessel) -> Result<Unit, string> = {
    CONSOLE.clear()

    // https://kontrolsystem2.readthedocs.io/en/latest/reference/ksp/vessel.html#part
    const science_modules : ModuleScienceExperiment[] = vessel.parts
        .filter(fn(part) -> part.science_experiment.defined)
        .map(fn(part) -> part.science_experiment.value)

    while(true) {
        CONSOLE.clear()
        const experiment = find_experiment(science_modules)
        if(experiment.defined) {
            CONSOLE.print_line("RUNNING EXPERIMENT: " + experiment.value.definition.id)
            experiment.value.run_experiment()
            wait_until(fn () -> experiment.value.current_running_time < 0)
        }
        yield()
    }
}

sync fn find_experiment(science_modules: ModuleScienceExperiment[]) -> Option<Experiment> = {
    for(science_module in science_modules) {
        for(experiment in science_module.experiments) {
            printScience(experiment)
            if(can_run(experiment)) {
                return Some(experiment)
            } 
        }
    }
    return None()
}

sync fn can_run(experiment : Experiment) -> bool = {
    if(experiment.current_experiment_state == ExperimentState.READY && 
       experiment.current_running_time >= 0) {
        return true
    }
    return false
}

sync fn printScience(experiment : Experiment) -> Unit = {
    CONSOLE.print_line(experiment.definition.id)
    CONSOLE.print_line("-----------------------------")
    CONSOLE.print_line(format("  --> Time to Complete: {0:N2}", experiment.time_to_complete))
    CONSOLE.print_line(format("  --> condition_met: {0}", experiment.condition_met))
    CONSOLE.print_line(format("  --> crew_required: {0}", experiment.crew_required))
    CONSOLE.print_line(format("  --> current_experiment_state: {0}", experiment.current_experiment_state))
    CONSOLE.print_line(format("  --> current_running_time: {0:N2}", experiment.current_running_time))
    CONSOLE.print_line(format("  --> previous_experiment_state: {0}", experiment.previous_experiment_state))
    CONSOLE.print_line(format("  --> current_situation_is_valid: {0}", experiment.current_situation_is_valid))
    CONSOLE.print_line(format("  --> time_to_complete: {0}", experiment.time_to_complete))
    CONSOLE.print_line(format("  --> has_enough_resources: {0}", experiment.has_enough_resources))
    CONSOLE.print_line(format("  --> region_required: {0}", experiment.region_required))
}

One thing I noticed is that in the game UI, the blinky science button in in the 'Vessel Actions' panel with the lights, gear, solar panels, etc. With the 0.2 update is science a new action group? It's not listed as an action group in the docs, but I'm not familiar with what's available from the game.

fbl100 avatar Feb 07 '24 02:02 fbl100

... I did a bit of deeper digging and noticed that ConditionMet seems to have a different meaning is only updated/changed infrequently. I will probably drop it from the API for now. The current_exeriment_state is somewhat surprising though and require a bit more testing

untoldwind avatar Feb 08 '24 13:02 untoldwind

Short observation: I added this to printScience:

    CONSOLE.print_line(format("  --> region_required: {0}", experiment.region_required))
    if (Some(location) = experiment.experiment_location) {
        CONSOLE.print_line(format("  --> experiment_location.body_name: {0}", location.body_name))
        CONSOLE.print_line(format("  --> experiment_location.science_region: {0}", location.science_region))
        CONSOLE.print_line(format("  --> experiment_location.science_situation: {0}", location.science_situation))
    }
}

It looks like experiment.experiment_location is initially empty and filled with information of the previous run.

In the API I found a field to get the science/research_location the vessel currently is in, i.e. this will work with the next patch:

        const vessel_location = vessel.research_location
        CONSOLE.print_line(format("  --> vessel.location.body_name: {0}", vessel_location.body_name))
        CONSOLE.print_line(format("  --> vessel.location.science_region: {0}", vessel_location.science_region))
        CONSOLE.print_line(format("  --> vessel.location.science_situation: {0}", vessel_location.science_situation))

So I guess the logic would be: Experiment shall run if:

  • experiment.current_experiment_state == READY
    • and
      • experiment.experiment_location is empty
      • or experiment.experiment_location is defined but differs from vessel.research_location

This is a bit convoluted and I am still looking for a way to make the research inventory accessible as well.

untoldwind avatar Feb 08 '24 18:02 untoldwind

Thanks for taking a look. I agree that it's a bit convoluted, but.. early access.

Is the 'research inventory' that you're looking into the list of science/research that you've already completed?

I'll give this a whirl when the next patch comes out.

fbl100 avatar Feb 08 '24 19:02 fbl100

After some testing I made vessel.research_location as it might be undefined. Here is some test code that should work with 0.5.2.7:

        if(Some( vessel_location) = vessel.research_location) {
            CONSOLE.print_line(format("  --> vessel.location.body_name: {0}", vessel_location.body_name))
            CONSOLE.print_line(format("  --> vessel.location.science_region: {0}", vessel_location.science_region))
            CONSOLE.print_line(format("  --> vessel.location.science_situation: {0}", vessel_location.science_situation))
        }

Additionally there is vessel.science_storage to access the research inventory and trigger transmission of experiment data.

    const storage = vessel.science_storage.value

    for(report in storage.research_reports) {
        CONSOLE.print_line(report.definition.id)
        CONSOLE.print_line(report.definition.display_name)
        CONSOLE.print_line(report.transmission_percentage.to_string())
        CONSOLE.print_line(report.time_required.to_string())
        CONSOLE.print_line(format("  --> experiment_location.body_name: {0}", report.research_location.body_name))
        CONSOLE.print_line(format("  --> experiment_location.science_region: {0}", report.research_location.science_region))
        CONSOLE.print_line(format("  --> experiment_location.science_situation: {0}", report.research_location.science_situation))
    }

    storage.start_transmit_all()

untoldwind avatar Feb 09 '24 17:02 untoldwind

version 0.5.2.8 (Ckan)

As I was boring last night, I take a look to science. In anycase it could be usefull, with the same ugly vessel (Except, I change the Z-200 battery pack for a Z-1K battery pack) thoses functions seems to do the job.

_gitreport::basicscience.to2

use { CONSOLE } from ksp::console
use { Vessel, ModuleScienceExperiment, VesselSituation } from ksp::vessel
use { ExperimentState, Experiment, ResearchLocation, ResearchReport, ScienceSituation } from ksp::science
use { wait_until, yield } from ksp::game
use { round } from core::math

/// Entry Point
pub fn main_flight(vessel: Vessel) -> Result<Unit, string> = {
    CONSOLE.clear()

    // https://kontrolsystem2.readthedocs.io/en/latest/reference/ksp/vessel.html#part
    const science_modules = vessel.parts
        .filter(fn(part) -> part.science_experiment.defined)
        .map(fn(part) -> part.science_experiment.value)

    // get parachutes
    const parachutes = vessel.parts
        .filter(fn(part) -> part.parachute.defined)
        .map(fn(part) -> part.parachute.value)

    check_science(vessel)
    wait_until(fn() -> (!science_running(vessel)))
    check_science(vessel)

    // take off
    vessel.set_throttle(0.55)
    vessel.staging.next()
    wait_until(fn() -> vessel.staging.ready)



    // while going up
    while(round( vessel.up.dot(vessel.surface_velocity) ) >= 0) {
        if(vessel.engines.exists(fn(engine) -> engine.is_flameout)) { // drop engine
            vessel.staging.next()
            wait_until(fn() -> vessel.staging.ready)
        }

        check_science(vessel)

        yield() // let Unity do things
    }

    // arm parachutes
    for(parachute in parachutes)
        parachute.armed = true

    // while going down
    while(vessel.situation != VesselSituation.Landed){
        check_science(vessel)
        yield() // let Unity do things
    }

    // just in case anything new could be catch
    check_science(vessel)
    wait_until(fn() -> (!science_running(vessel)))
    check_science(vessel)

    CONSOLE.print_line(vessel.name + ": end of mission")
}

fn check_science(vessel: Vessel, autoSend: bool = true, verbose: bool = true) -> Unit = {
    const locationComparison = fn(locA: ResearchLocation, locB: ResearchLocation) -> {
        (locA.body_name == locB.body_name || locA.body_name.length == 0 || locB.body_name.length == 0)
        && (locA.science_region == locB.science_region || (!locA.requires_region) || (!locB.requires_region))
        && (locA.science_situation == locB.science_situation || locA.science_situation == ScienceSituation.None || locB.science_situation == ScienceSituation.None)
    }
    const storedReports =
        if(vessel.science_storage.defined)
            vessel.science_storage.value.research_reports
        else
            <ResearchReport>[]

    if(Some(shipLocation) = vessel.research_location) {
        const newExperiments = vessel.parts
            .filter(fn(p) -> p.science_experiment.defined)
            .map(fn(p) -> p.science_experiment.value.experiments
                .filter(fn(e) -> e.current_experiment_state == ExperimentState.READY
                    && ((!e.experiment_location.defined) || (!locationComparison(e.experiment_location.value, shipLocation))))
            ).reduce(<Experiment>[], fn(flat, arr) -> flat + arr)
            .filter(fn(e) -> !storedReports.exists(fn(r) -> r.definition.id == e.definition.id && (locationComparison(r.research_location, shipLocation))))
        for(e in newExperiments) {
            if(verbose)
                CONSOLE.print_line("Starting " + e.definition.id + " at " + shipLocation.body_name + "/" + shipLocation.science_situation.to_string() + "/" + shipLocation.science_region)
            e.run_experiment()
        }
    }
    if(autoSend) {
        for(r in storedReports.filter(fn(r) -> r.transmission_percentage == 0.0 && r.transmission_size > 0.0 && (!r.transmission_status))) {
            if(verbose)
                CONSOLE.print_line("Emitting " + r.definition.id + " from " + r.research_location.body_name + "/" + r.research_location.science_situation.to_string() + "/" + r.research_location.science_region)
            r.start_transmit()
        }
    }
}

sync fn science_running(vessel: Vessel) -> bool = {
    vessel.parts
        .filter(fn(p) -> p.science_experiment.defined)
        .map(fn(p) -> p.science_experiment.value)
        .exists(fn(m) -> m.experiments.exists(fn(e) -> e.current_experiment_state == ExperimentState.RUNNING))
}

It trigger research for any new compatible location. Caution, it doesn't look at battery capacity, so it's easy to be short on juice. I think the code is simple enought to split the emission part if needed.

Edit : typo

lefouvert avatar Feb 20 '24 17:02 lefouvert

I guess the localComparison condition and the newExperiments filter could be add as helper functions to the std:: lib.

But first I have to do a bit more testing with the current pre-release (pretty much every file was touched by the refactoring session last weekend ;) )

untoldwind avatar Feb 21 '24 19:02 untoldwind

Hi everyone! I had a similar script (badly written because I don't know C# language and I didn't recall the .map and .filter method). I didn't thought at the empty location as a condition to run an experiment! Nice touch! Thanks for that.

I'm going farther with the initial question: is it possible to know if an experiment was already conducted in a previous flight? KSP's latest version corrected that (the button doesn't blink anymore) when the experiment has been already done. Science Archive Mod also keeps track of the done experiment from one flight to an other. I assume something in KSP's API allows that.

Thanks a lot for that mod. More complex than kOS but I'm having lot of fun to figure out how things work!

PhilouDS avatar Feb 23 '24 18:02 PhilouDS

To my knowledge, there is (still) no way to know what is already studied in KSC. Note KOS scripts are not C#. As far as I know, the mod is written in C#, easiest way to talk to Unity, the game engine, but KOS script seems to be more 'Rust' inspired language (maybe I'm wrong, it's pure gessing)

As a candy, to wait, I can give you a well splited, slightly simpler version of the previous code :

use { CONSOLE } from ksp::console
use { Vessel, ModuleScienceExperiment, VesselSituation } from ksp::vessel
use { ExperimentState, Experiment, ResearchLocation, ResearchReport, ScienceSituation } from ksp::science
use { ResourceData } from ksp::resource
use { wait_until, yield } from ksp::game
use { round } from core::math

pub type ResourceConst = int

pub const Resource: (MP: ResourceConst, SF: ResourceConst, Air: ResourceConst, H: ResourceConst, CH4: ResourceConst, Ox: ResourceConst, EC: ResourceConst, Xe: ResourceConst) = (
    MP: 1,
    SF: 2,
    Air: 3,
    H: 6,
    CH4: 7,
    Ox: 8,
    EC: 12,
    Xe: 13
)

pub fn check_science(vessel: Vessel, autoSend: bool = true, verbose: bool = true) -> Unit = {
    const locationComparison = fn(locA: ResearchLocation, locB: ResearchLocation) -> {
        (locA.body_name == locB.body_name || locA.body_name.length == 0 || locB.body_name.length == 0)
        && (locA.science_region == locB.science_region || (!locA.requires_region) || (!locB.requires_region))
        && (locA.science_situation == locB.science_situation || locA.science_situation == ScienceSituation.None || locB.science_situation == ScienceSituation.None)
    }
    const storedReports =
        if(vessel.science_storage.defined)
            vessel.science_storage.value.research_reports
        else
            <ResearchReport>[]
    if(Some(shipLocation) = vessel.research_location) {
        const newExperiments = vessel.parts
            .filter(fn(p) -> p.science_experiment.defined)
            .map(fn(p) -> p.science_experiment.value.experiments
                .filter(fn(e) -> e.current_experiment_state == ExperimentState.READY
                    && e.current_experiment_state != ExperimentState.ALREADYSTORED
                    && ((!e.experiment_location.defined) || (!locationComparison(e.experiment_location.value, shipLocation))))
            ).reduce(<Experiment>[], fn(flat, arr) -> flat + arr)
        run_science(vessel, newExperiments, verbose)
    }
    if(autoSend)
        emmit_science(vessel, storedReports, verbose)
}

pub sync fn science_running(vessel: Vessel) -> bool = {
    vessel.parts
        .filter(fn(p) -> p.science_experiment.defined)
        .map(fn(p) -> p.science_experiment.value)
        .exists(fn(m) -> m.experiments.exists(fn(e) -> e.current_experiment_state == ExperimentState.RUNNING))
}

fn run_science(vessel: Vessel, experiments: Experiment[], verbose: bool = true) -> bool = {
    if(Some(shipLocation) = vessel.research_location) {
        if(verbose) {
            for (e in experiments)
                CONSOLE.print_line("Starting " + e.definition.id + " at " + shipLocation.body_name + "/" + shipLocation.science_situation.to_string() + "/" + shipLocation.science_region)
        }
        return experiments
            .map(fn(e) -> e.run_experiment())
            .exists(fn(done) -> done)
    }
    return false
}

fn emmit_science(vessel: Vessel, reports: ResearchReport[], verbose: bool = true) -> bool = {
    const toSendReports = reports
        .filter(fn(r) -> r.transmission_percentage == 0.0 && r.transmission_size > 0.0 && (!r.transmission_status))
        .reduce((reports: <ResearchReport>[], consumption: 0.0), fn(agg, r) -> if(agg.consumption + r.ec_required < available_power(vessel)) (reports: agg.reports + r, consumption: agg.consumption + r.ec_required) else (reports: agg.reports, consumption: agg.consumption))
    if(verbose) {
        for (r in toSendReports.reports)
                CONSOLE.print_line("Emitting " + r.definition.id + " from " + r.research_location.body_name + "/" + r.research_location.science_situation.to_string() + "/" + r.research_location.science_region)
    }
    return toSendReports.reports
        .map(fn(r) -> r.start_transmit()) // ugly, but not sure if exists short the search at the first true
        .exists(fn(done) -> done)
}

sync fn available_power(vessel: Vessel) -> float = {
    vessel.parts
        .reduce(<ResourceData>[], fn(flat, p) -> flat + p.resources.list.filter(fn(r) -> r.resource.id == Resource.EC))
        .reduce(0.0, fn(sum, r) -> sum + r.stored_units)
}

It consider to not emiting a report if EC resource are not enought. It DON'T check for running experience since there (still ?) is no numeric data for the EC consumption (only a has_enough_resources which is not enough to know if multiple experiences are runnable.) or solar panels max supply.

I'm not totaly confident with the e.current_experiment_state != ExperimentState.ALREADYSTORED instead of .filter(fn(e) -> !storedReports.exists(fn(r) -> r.definition.id == e.definition.id && (locationComparison(r.research_location, shipLocation))) but it's simpler to write, to read, and did give good result last ten flight... Had take a (short) look at ExperimentState.INVALIDLOCATION and ExperimentState.LOCATIONCHANGED and results are not convincing, so at the time, I'll keep the locationComparison lamda.

lefouvert avatar Feb 24 '24 00:02 lefouvert

THanks for your script @lefouvert I have one "solution" but I don't know how to do. Each time an experiment is done and data transmitted, I want to write the name of that experiment (and its location/region...) in a txt file (a CSV file might be better). Then, I just have to check if the science is in the text file. This way, I have access to all the science from flight to flight. But I don't know how to create a new file and how to read it :( Is it possible to do that with Kontrol System?

PhilouDS avatar Feb 24 '24 09:02 PhilouDS

The two only ways I found to wrote a file are

  • saving a telemetry series (ksp::telemetry::save_time_series), but you don't have the ability to read it back. (maybe i'll give it a try to have «blackbox logs» of my flights somedays)
  • write a debug message via core::logging functions, and still, you dont have the ability to read them.

IMHO, none of thoses ways are usable.

lefouvert avatar Feb 24 '24 13:02 lefouvert

There are some (rough) guidelines what a KSP2 mod is allowed and not allowed to do, so reading and writing files has to be done with care. I guess the save_lime_series is already on the edge of a gray area in this regard.

What probably would be within the allowed bounds would be some kind of persistent key-value store somewhere in the module directory ... just like the scripts themselves. I think I will add this to the todo-list.

For the problem at hand though. For the next release I added a get_completed_research_reports() to ksp::science to access everthing that has been handed in so far. From what I can tell internally the value of an experiment is matched via experiment_id, research_location_id and research_type (... made of those available as well).

untoldwind avatar Feb 24 '24 15:02 untoldwind

@untoldwind Out of curiosity, where thoses guidelines can be found ?

lefouvert avatar Feb 24 '24 17:02 lefouvert

I guess this one: https://forum.kerbalspaceprogram.com/topic/154851-add-on-posting-rules-april-13-2021/

untoldwind avatar Feb 24 '24 17:02 untoldwind

In 0.5.3.2 this should work:

use { Vessel } from ksp::vessel
use { get_completed_research_reports } from ksp::science
use { CONSOLE } from ksp::console

/// Entry Point
pub fn main_flight(vessel: Vessel) -> Result<Unit, string> = {
    CONSOLE.clear()

    const completed = get_completed_research_reports()

    for(report in completed) {
        CONSOLE.print_line(report.definition.id)
        CONSOLE.print_line(report.experiment_id)
        CONSOLE.print_line(report.research_location_id)
        CONSOLE.print_line(report.science_value.to_string())
    }
}

experiment_id and research_location_id should correspond to the id fields in ExperimentDefinition and ResearchLocation

untoldwind avatar Feb 24 '24 18:02 untoldwind

It works very well! Fantastic! Thanks

PhilouDS avatar Feb 24 '24 19:02 PhilouDS

It looks like you don't have access do the details (region, situation) of Research Location for the completed research report. So we can't ue the locationComparison from @lefouvert. The id seems to be in the form body_situation_region or body_situation when region is not required. So I tried this:

fn exp_loc_id (craft: Vessel, exp: Experiment, short: bool = false) -> string = {
  let exp_body_id = craft.research_location.value.body_name
  
  let exp_situation_id = exp.valid_locations.filter(
    fn(loc) -> loc.id == ("_" + craft.research_location.value.science_situation.to_string())
  )[0].id
  
  let exp_region_id = "_" + craft.research_location.value.science_region

  if (short) {
    return (exp_body_id + exp_situation_id)
  }
  else {
    return (exp_body_id + exp_situation_id + exp_region_id)
  }
}

Then, I use this to compare an experiment with the experiment already reported:

fn reported_previous_flight (craft: Vessel, exp: Experiment) -> bool = {
  const science_completed = get_completed_research_reports()
  let rep_previous = false

  if (science_completed.length != 0) {
    for (rep in science_completed) {
      if ((rep.experiment_id == exp.definition.id) &&
          ((rep.research_location_id == exp_loc_id(craft, exp)) ||
          (rep.research_location_id == exp_loc_id(craft, exp, true)))) {
        rep_previous = true
      }
    }
  }

  return rep_previous
}

Because experiments done during the actual flight are not in the completed research reports, I have the same kind of function for the actual flight:

fn reported_this_flight (craft: Vessel, exp: Experiment) -> bool = {
  const research_inventory = craft.science_storage.value.research_reports
  let rep_this = false
  
  if (research_inventory.length != 0) {
    for (rep in research_inventory) {
      if ((rep.experiment_id == exp.definition.id) &&
          ((rep.research_location_id == exp_loc_id(craft, exp)) ||
          (rep.research_location_id == exp_loc_id(craft, exp, true)))) {
        rep_this = true
      }
    }
  }

  return rep_this
}

and I finish with this to know if the exp is new:

fn check_new_exp (craft: Vessel, exp: Experiment) -> bool = {
  return (!reported_previous_flight(craft, exp) && !reported_this_flight(craft, exp))
}

All seem to work but I didn't try with multiple experiments in Exploration mode.

PhilouDS avatar Feb 25 '24 08:02 PhilouDS

@untoldwind Did ResearchReport lost the ability .start_transmit() to be individualy transmited with v0.5.3.2 or v.0.5.3.3 ? I only found the .start_transmit_all() on ScienceStorage.

lefouvert avatar Feb 26 '24 08:02 lefouvert

Just realized that it accidentally dropped out during one of the refactoring. Created a hotfix: 0.5.3.4 which should contain it again

untoldwind avatar Feb 26 '24 10:02 untoldwind

This issue is stale because it has been open for 60 days with no activity.

github-actions[bot] avatar Apr 27 '24 02:04 github-actions[bot]

This issue was closed because it has been inactive for 14 days since being marked as stale.

github-actions[bot] avatar May 11 '24 02:05 github-actions[bot]