Open awp3rator opened 7 years ago
I had posted some replies to address this request, however, since taking some time away from the computer and stepping back from the problem to think about it, I've come up with an improved and more efficient version of my original suggestion. CMDR McDonald may have something better to offer, but in the mean time here's my version.
It is set to a limit of listing five commodities before giving just a total (at six or more), but this can be altered to suit your choice. It will also simply say that you can sell all of your cargo for a profit, if every commodity on board will sell for a profit (excluding stolen, mission or limpet cargo).
Just copy the whole thing and replace the whole Commodity Sale Check script.
{_ Function to find a given commodity in market}
{set market(commodity) to:
{for marketcommodity in station.commodities:
{if marketcommodity.EDDBID = commodity.EDDBID:
{return marketcommodity}
}
}
}
{_ set this as your max to list before total is used instead}
{set maxcommoditycount to 5}
{set carryingstolencargo to 0}
{set profitablecargo to 0}
{set cargostring to ""}
{for cargo in ship.cargo:
{if cargo.stolen:
{set carryingstolencargo to carryingstolencargo + 1}
|elif cargo.commodity.name != 'Limpet' && !cargo.missionid:
{set marketcommodity to market(cargo.commodity)}
{if marketcommodity && marketcommodity.demand > 0 && marketcommodity.sellprice && marketcommodity.sellprice > cargo.price:
{set profit to marketcommodity.sellprice - cargo.price}
{set totalprofit to totalprofit + profit}
{set cargostring to cat(cargostring," your ",cargo.commodity.name," for ",profit," credits profit,")}
{set profitablecargo to profitablecargo + 1}
}
}
}
{if profitablecargo > 0 && profitablecargo = len(ship.cargo) - carryingstolencargo:
You can sell all of your
{if carryingstolencargo > 0: {OneOf("legal","legitimate")} }
cargo {Occasionally(2,"commodities")} here for a total profit of {totalprofit} credits.
|elif profitablecargo > maxcommoditycount:
You can sell {profitablecargo} commodities here for a total profit of {totalprofit} credits.
|elif profitablecargo > 0:
You can sell {cargostring}.
}
{if carryingstolencargo > 0:
Reminder: you {OneOf("have stolen cargo on-board", "have stolen goods on-board", "are carrying stolen goods", "are carrying stolen cargo")}.
}
I believe this will do exactly what you need. I've tested it out and it works very well. Although, I may not have caught every bug in my code.
That's fantastic thanks! I will test it out. I was arriving at a similar set of logic for the cargo maths, but hadn't considered the stolen cargo or limpets. Nice touch.
You're welcome! :) And if CMDR McDonald likes it enough too, he's more than welcome to use it in future updates to EDDI.
Working like a charm on a mining run with 6 commodities at a profit of over 170,000 credits. I was also carrying limpets and a stolen trade canister, for good measure. The number of commodities and total profit were spot on!
The credit goes to CMDR McDonald, it is primarily his code after all. I just made some alterations to provide a solution to your problem. I will certainly be using it myself from now on though, so thank you for requesting it otherwise I may not have thought about doing it.
I'm also considering updating it to provide a simple 'You can sell your illegal cargo for X credits at the local black market', if there is one at the current station. Or something along those lines anyway. I'm not home right now, but will look into it later.
I've updated the script and fixed a couple of potential problems in rare cases. This should be a bit more robust now.
Can you test the stolen goods part? I can't seem to get it to work. The cargo.stolen Boolean value seems to always resolve as False, no matter how many stolen commodities I am carrying. However, the Boolean for 'station.hasblackmarket' seems to work fine, so I'm not sure what's happening.
{_ Function to find a given commodity in market}
{set market(commodity) to:
{for marketcommodity in station.commodities:
{if marketcommodity.EDDBID = commodity.EDDBID:
{return marketcommodity}
}
}
}
{_ set this as your max to list before total is used instead}
{set maxcommoditycount to 5}
{set carryingstolencargo to 0}
{set missioncargo to 0}
{set profitablecargo to 0}
{set cargostring to ""}
{for cargo in ship.cargo:
{if cargo.commodity.name != 'Limpet':
{set marketcommodity to market(cargo.commodity)}
{if cargo.stolen:
{set carryingstolencargo to carryingstolencargo + 1}
|elif cargo.missionid:
{set missioncargo to missioncargo + 1}
|elif marketcommodity && marketcommodity.demand > 0 && marketcommodity.sellprice && marketcommodity.sellprice > cargo.price:
{set profit to marketcommodity.sellprice - cargo.price}
{set totalprofit to totalprofit + profit}
{set cargostring to cat(", ",cargostring," your ",cargo.commodity.name," for ",profit," credits profit")}
{set profitablecargo to profitablecargo + 1}
}
}
}
{if profitablecargo > 0 && profitablecargo = len(ship.cargo) - carryingstolencargo - missioncargo:
You can sell all of your
{if carryingstolencargo > 0: {OneOf("legal","legitimate")} }
{if missioncargo > 0: non-mission}
cargo {Occasionally(2,"commodities")} here for a total profit of {totalprofit} credits.
|elif profitablecargo > maxcommoditycount:
You can sell {profitablecargo} commodit{if profitablecargo > 1:ies |else:y} here for a total profit of {totalprofit} credits.
|elif profitablecargo > 0:
You can sell {cargostring} per tonne.
}
{if carryingstolencargo > 0 || missioncargo > 0:
{if station.hasblackmarket:
{OneOf("This station has a Black Market,","There is a Black Market at this station,")},
{if carryingstolencargo > 0:
you may be able to {OneOf("sell","off-load")} your
{carryingstolencargo} {OneOf("stolen","illegal")}
{OneOf("cargo","commodit{if carryingstolencargo > 1:ies |else:y}")} here.
}
{if missioncargo > 0:
You {if carryingstolencargo > 0: may also |else: can}
sell your {missioncargo} mission {Occasionally(2," specific")}
{OneOf("cargo","commodit{if missioncargo > 1:ies |else:y}")} here if you wish.
}
|elif carryingstolencargo > 0:
Reminder: you {OneOf("have stolen cargo on-board", "have stolen goods on-board", "are carrying stolen goods", "are carrying stolen cargo")}.
}
}
I ran in to the same issue, where the stolen cargo was not registering. I think we need to qualify the "if cargo.stolen:" as true or false. Modifying the block to:
{for cargo in ship.cargo:
{if cargo.commodity.name != 'Limpet':
{set marketcommodity to market(cargo.commodity)}
{if cargo.stolen = true:
{set carryingstolencargo to carryingstolencargo + 1}
|elif cargo.missionid = true:
{set missioncargo to missioncargo + 1}
|elif marketcommodity && marketcommodity.demand > 0 && marketcommodity.sellprice && marketcommodity.sellprice > cargo.price:
{set profit to marketcommodity.sellprice - cargo.price}
{set totalprofit to totalprofit + profit}
{set cargostring to cat(", ",cargostring," your ",cargo.commodity.name," for ",profit," credits profit")}
{set profitablecargo to profitablecargo + 1}
}
}
}
Seems to correctly detect that I have the correct count of stolen commodities on board when landing at a station with a black market.
I was debugging with a simplified version, examples below:
Doesn't work:
{set carryingstolencargo to 0}
{for cargo in ship.cargo:
{if cargo.stolen:
{set carryingstolencargo to carryingstolencargo + 1}
}
}
Count of stolen cargo is {carryingstolencargo}
This works:
{set carryingstolencargo to 0}
{for cargo in ship.cargo:
{if cargo.stolen = true:
{set carryingstolencargo to carryingstolencargo + 1}
}
}
Count of stolen cargo is {carryingstolencargo}
Putting it all together.... I'm going to test with this version:
{_ Function to find a given commodity in market}
{set market(commodity) to:
{for marketcommodity in station.commodities:
{if marketcommodity.EDDBID = commodity.EDDBID:
{return marketcommodity}
}
}
}
{_ set this as your max to list before total is used instead}
{set maxcommoditycount to 5}
{set carryingstolencargo to 0}
{set missioncargo to 0}
{set profitablecargo to 0}
{set cargostring to ""}
{for cargo in ship.cargo:
{if cargo.commodity.name != 'Limpet':
{set marketcommodity to market(cargo.commodity)}
{if cargo.stolen = true:
{set carryingstolencargo to carryingstolencargo + 1}
|elif cargo.missionid = true:
{set missioncargo to missioncargo + 1}
|elif marketcommodity && marketcommodity.demand > 0 && marketcommodity.sellprice && marketcommodity.sellprice > cargo.price:
{set profit to marketcommodity.sellprice - cargo.price}
{set totalprofit to totalprofit + profit}
{set cargostring to cat(", ",cargostring," your ",cargo.commodity.name," for ",profit," credits profit")}
{set profitablecargo to profitablecargo + 1}
}
}
}
{if profitablecargo > 0 && profitablecargo = len(ship.cargo) - carryingstolencargo - missioncargo:
You can sell all of your
{if carryingstolencargo > 0: {OneOf("legal","legitimate")} }
{if missioncargo > 0: non-mission}
cargo {Occasionally(2,"commodities")} here for a total profit of {totalprofit} credits.
|elif profitablecargo > maxcommoditycount:
You can sell {profitablecargo} commodit{if profitablecargo > 1:ies |else:y} here for a total profit of {totalprofit} credits.
|elif profitablecargo > 0:
You can sell {cargostring} per tonne.
}
{if carryingstolencargo > 0 || missioncargo > 0:
{if station.hasblackmarket:
{OneOf("This station has a Black Market,","There is a Black Market at this station,")},
{if carryingstolencargo > 0:
you may be able to {OneOf("sell","off-load")} your
{carryingstolencargo} {OneOf("stolen","illegal")}
{OneOf("cargo","commodit{if carryingstolencargo > 1:ies |else:y}")} here.
}
{if missioncargo > 0:
You {if carryingstolencargo > 0: may also |else: can}
sell your {missioncargo} mission {Occasionally(2," specific")}
{OneOf("cargo","commodit{if missioncargo > 1:ies |else:y}")} here if you wish.
}
|elif carryingstolencargo > 0:
Reminder: you {OneOf("have stolen cargo on-board", "have stolen goods on-board", "are carrying stolen goods", "are carrying stolen cargo")}.
}
}
Hmm, I thought I'd tried that, but I'll give it another go, just as you have it here.
I've also found that the script only looks at what a station wants to buy or sell. If you have something that the station doesn't normally want or provide, even if you can sell it here for a profit, it won't tell you. For example, I picked up a legal occupied cryopod and some algae, went to a station, and while I could sell them for pure profit, the script didn't tell me as the station didn't normally deal in those. I've also found this to be the case when hauling rare goods and engineer specific commodities.
I'm not sure what to do about these as the script gets it's market information in the very first bit of code, and takes it direct from the stations buy/sell list. I've wondered if there is a way to only check what you are hauling against what the station will buy it for, but I'm not that good at this yet.
I also found a glitch. I was going to sell Polymers and the script told me I could sell it. This is fine, except that the station was supplying it and it wasn't in demand. When error checking, I found that the 'marketcommodity.demand' was actually set at 1, while the station supply was well over 3,000 with zero demand. Not sure if this was a one-off or not, I'll need to keep an eye on things and see if it happens again.
On another note, I've made a couple of slight adjustments to my script to make a couple of lines sound much better:-
{set cargostring to cat(cargostring," your ",cargo.commodity.name," for ",profit," credits profit. ")}
and
|elif profitablecargo > 0:
You can sell {cargostring}
}
After listening to these in the previous form, I thought they sounded too rushed and making these slight adjustments makes things clearer.
I've just tried the {if cargo.stolen = true: and it still doesn't work for me. The cargo.stolen is always resolving as false.
I have three commodities on board: 2 Uraninite (stolen), 15 Xihe Biomorphic Companions (rare good), and 9 Non-Lethal Weapons (bought for a mission). When I first landed at an outpost with a black market, the script told me I could sell the Non-Lethal weapons and that was it, nothing else. I then ran a test of the script and now it tells me I can sell both the Non-Lethal Weapons AND the stolen Uraninite as LEGAL commodities.
I have cleared the %APPDATA% directory, reinstalled EDDI, set it up again and copied the script into a new personality, and it still says the same thing, two legal commodities and no stolen ones. Same goes for the default script.
I have added the following code to test, right after the line {set marketcommodity to market(cargo.commodity)}.
Name {cargo.commodity.name}.
Defined: {defined(cargo.stolen)}.
Cast: {cast(cargo.stolen,"n")}.
This tells me that cargo.stolen is defined for each of the three commodities, however it is always defined as 0, 'false',
However, I've also tried this code:
{set test to true}
Cast test: {cast(test,"n")}.
This also tells me that test is 'zero', or "false". So this isn't setting the Boolean value correctly.
And to make sure this 'Cast' is working I tried this:
Cast test: {cast(station.hasblackmarket,"n")}.
And this tells me that it's 'one', or "true". So this is working perfectly, and I'm really confused. I have no idea why it's not working for me, but works for you. And with the test results I have, I'm wondering if the 'station.hasblackmarket' is being defined in a different way to the 'cargo.stolen' variable.
If CMDR McDonald could weigh in on this and provide some insight, it would be very much appreciated.
I sold my normal cargo and only have two stolen on board now. I've just tried these:
{if cargo.stolen = false:
Nothing happens.
{if cargo.stolen != false:
Tells me I can sell my stolen cargo, which would normally be correct as this is 'not false'. However....
{if cargo.stolen != true:
Also tells me I can sell my stolen cargo, which is wrong as this is 'false'.
This is making me crazy as to why it's not working....
Edit: I've just tried all this thread on a second PC and I get exactly the same results. :(
This is due to cottle not providing native boolean types. I've put in functions for 'true' and 'false' for the next release of EDDI so that these will work as expected; if you want this to work before that then you can just use 0 and 1 instead of true and false.
I've just tried both of these {if cargo.stolen = 1: and {if cargo.stolen = 0: and neither of them worked. My stolen cargo is still considered as legal when taken to a black market. This is in both my script and the EDDI default (copied as a new personality).
Thank you for all of your changes for this event. 2.1.1-b4 has an altered script that provides only a single sentence regardless of the number of commodities that can be sold for profit. Feel free to test this if and let me know how it is going if you have the beta, otherwise it will be released in 2.1.1
Thanks. I'm in the middle of a mining run right now, so I'll see how it goes when I return to sell my cargo.
I took a quick look over and noticed what seems to be a small typo. You have ('offload, dump', 'fence'). Should it not be ('offload', 'dump', 'fence')?
First I want to say thank you for the new script, and also to apologise for the following wall of text.
I've tested the new script and it works very well. While it does shorten the overall spoken sentence, it doesn't do what we were looking for. We wanted a variable cut-off point where an amount of commodities over the threshold would simply say 'X commodities for Y profit'. This is most useful when mining (or piracy) when you will have many different commodites and don't want to hear them all listed. This shouldn't affect traders, as people normally trade in one or two commodities at a time anyway.
I don't mean to 'step on your toes' with my script, and I certainly don't consider mine 'superior' to yours, as we are looking for different things in what this script provides. It looks like you wish the simplicity of just saying what you can sell for profit, while the others and myself want more (or less) information depending on the situation.
I've merged my script and your new one to provide what we need. It also makes what I consider to be a few improvements and changes, and here is my reasoning behind those.
Misson commodities. These are counted, so they can be discounted when looking at selling everything. Of course this only applies as my script allows for a single 'you can sell everything for Y profit' sentence over the set threshold, as mission commodities can't be sold.
Also, if I've failed a mission, I'd like to know if I can get rid of the mission cargo for a few credits rather than dump it in deep space.
Null commodities. Not all commodites are in the stations market list obtained at the beginning of the script, even though they can still be sold there. Minerals like Osmium and Praseodymium, or some engineering commodities, are 'null' and so are not counted towards the profitable cargo. This could simply be because they are neither in demand OR supply, I'm not sure. My script counts these and informs the Commander that they have such cargo on board. The default script ignores these commodities entirely, even if they can be sold for a profit.
If this is a bug that can be fixed, then the 'null' sections can be removed.
My 'while' loops. Mine make it unecessary to have multiple IF statements for one or two or multiple items of profitable commodities. These will all work within the one while loop. Although, I think your version may require less processing power/time?
Market commodity demand. Right, this one is a bit more complex. I came across a bug in the demand/supply where sometimes (not sure if every time) a commodity that is in supply (and has no demand) in the market, is still assigned a demand of 1 and with null supply. If this is an EDDI bug or a problem with the companion app, I don't know.
This means that even if a commodity is in supply at a station, the default script, and my one, counts it towards profitable cargo, particularly if you got it for free, like when mining. This is actually ok if you are looking for all cargo that will give a profit, rather than what cargo will give best profit. Obviously, a commodity in supply will not be as profitable as if it were in demand.
For example, I've just finished a mining run, and Gold, Silver & Gallite were all considered as a demand of 1 with no supply by the script. In reality, the market had Gold at a supply of 823, Silver at 1411, and Gallite at 12197, with no demand for any of them. This meant that all three were considered as profitable commodities. In fact, I didn't have anything on board that was in supply and not have demand of 1 and supply of null.
Just as a thought, could this be a bug in EDDI, not assigning supply correctly? Or the companion app not supplying the correct information? I've not tested every occasion I've been selling items, but it's possible that all commodities in supply are like this.
I've made the check '|elif marketcommodity && marketcommodity.sellprice > cargo.price:' so that anything that's profitable will be included, it doesn't matter if it's in demand or not. This also means that you don't need the {if profit > 0: line, as it's taken care of in this initial check. Checking if marketcommodity.demand > 0 (so far) seems to always be true, even if the commodity is not in demand at all.
As a band-aid 'fix' for this, you could make the check marketcommodity.demand > 1. This will correct the check to only consider commodities in real demand and ignore ones in supply, as originally intended, because most items in real demand are much more than only 1. The obvious downside to this is when a commodity genuinely is in demand by only 1, but this is rare.
Personally, I prefer the script to list everything that is profitable, even if it's not in demand.
Timing of the script. This is less to do with the actual script itself, and more to do with where it is called from. I've found that if I put the call to the script in the 'Market information updated' event, instead of in the 'Docked' event, then the information it provides is accurate. Last night I accidentally had the call in both, and when it was called it gave different information in both cases. However, the one in the 'Market' event was correct and the 'Docked' one was wrong. The only downside to this is that the 'Market' event is usually several seconds before it's triggered after docking, but this can be countered with something like "Checking market data, please wait" at the end of the 'Docked' event script, and "Data update complete" at the start of the 'Market' event script. I have something similar to that in my scripts.
Further to this, I've also moved the Purchase, Swapout and Limpet checks to the 'Market' script to keep everything tidy, and hopefully, more accurate. Basically, I moved the last half of the Docked script to the Market script.
Stolen Commodity reminder. I've left the reminder about stolen cargo in, as I've often forgotten, or not realised, I have picked up stolen commodities. I find this useful.
Well, anyway, I think that's everything I wanted to say. Here's my version of the script. I've not got around to testing the stolen commodities in a black market yet, or trying it with mission cargo, but I don't think there will be any problems as it worked in the previous versions. It is a little bigger than the default script, but that's because it does more. I'm also keeping the call to this script in my 'Market information updated' event as it's much more accurate there.
{_ Function to find a given commodity in market}
{set market(commodity) to:
{for marketcommodity in station.commodities:
{if marketcommodity.EDDBID = commodity.EDDBID:
{return marketcommodity}
}
}
}
{_ set this as your max to list before total is used instead}
{set maxcommoditycount to 5}
{set totalprofit to 0}
{set profitablecommodities to []}
{set stolencommodities to []}
{set missioncommodities to []}
{set nullcommodities to []}
{for cargo in ship.cargo:
{if cargo.commodity.name != 'Limpet':
{set marketcommodity to market(cargo.commodity)}
{if cargo.stolen = true:
{set stolencommodities to cat(stolencommodities, [cargo.commodity])}
|elif cargo.missionid:
{set missioncommodities to cat(missioncommodities, [cargo.commodity])}
|elif marketcommodity = null:
{set nullcommodities to cat(nullcommodities, [cargo.commodity])}
|elif marketcommodity && marketcommodity.sellprice > cargo.price:
{set totalprofit to totalprofit + ((marketcommodity.sellprice - cargo.price) * cargo.amount)}
{set profitablecommodities to cat(profitablecommodities, [cargo.commodity])}
}
}
}
{if len(profitablecommodities) > 0 && len(profitablecommodities) = len(ship.cargo) - len(stolencommodities) - len(missioncommodities):
You can sell all of your
{if len(stolencommodities) > 0: {OneOf("legal","legitimate")} }
{if len(missioncommodities) > 0: non-mission}
cargo {Occasionally(2,"commodities")} here for a total profit of {totalprofit} credits.
|elif len(profitablecommodities) > maxcommoditycount:
You can sell {len(profitablecommodities)} commodit{if len(profitablecommodities) > 1:ies |else:y} here for a total profit of {totalprofit} credits.
|elif len(profitablecommodities) > 0:
{set cur to 0}
You can sell your
{while cur < len(profitablecommodities):
{profitablecommodities[cur].name}
{set cur to cur + 1}
{if cur < len(profitablecommodities)-1:
,
|elif cur = len(profitablecommodities)-1:
and
}
}
for a profit of {totalprofit} credits.
}
{if len(nullcommodities) > 0:
{Pause(200)}
{set cur to 0}
Your cargo of
{while cur < len(nullcommodities):
{nullcommodities[cur].name}
{set cur to cur + 1}
{if cur < len(nullcommodities)-1:
,
|elif cur = len(nullcommodities)-1:
and
}
}
are not
{OneOf("listed at {OneOf('this station','the local market')}",
"on the {OneOf('local markets','stations')} normal {OneOf('list of commodities','commodity list')}")},
{if state.nullcommoditiestoday != 1:
You may be able to sell these here, but
{SetState("nullcommoditiestoday",1)}
}
{OneOf("profit is not guaranteed","profits are uncertain","these may be unprofitable")}.
}
{if len(stolencommodities) > 0 || len(missioncommodities) > 0:
{Pause(200)}
{if station.hasblackmarket:
{OneOf("This station has a Black Market,","There is a Black Market at this station,")},
{if len(stolencommodities) > 0:
you may be able to {OneOf("sell","off-load","dump","fence")} your
{len(stolencommodities)} {OneOf("stolen","illegal")}
{OneOf("cargo","commodit{if len(stolencommodities) > 1:ies |else:y}")} here.
}
{if len(missioncommodities) > 0:
{Pause(200)}
You {if len(stolencommodities) > 0: may also |else: can}
sell your {len(missioncommodities)} mission {Occasionally(2," specific")}
{OneOf("cargo","commodit{if len(missioncommodities) > 1:ies |else:y}")}
here if you wish, but this will fail the mission.
}
|elif len(stolencommodities) > 0:
Reminder: you {OneOf("have stolen cargo on-board", "have stolen goods on-board", "are carrying stolen goods", "are carrying stolen cargo")}.
}
}
Wow.... just wow... :P
Darkcyde13,
First of all, thank you for your work on this. I'm really enjoying the customizability of the Elite Dangerous experience through VA and EDDI. Is there a reference for the programming language that is being used in EDDI somewhere that I can read up on? To use your routine, I guess we would only need to change the maxcommoditycount to whatever we want?
mikelimtw,
There is a link in the help for EDDI that goes to a web page detailing all the Cottle commands, this is where I get much of my information. http://r3c.github.io/cottle/#toc-2
And, yes, change maxcommoditycount to whatever you like. If the total number of profitable commodities is over this number, then it will say "X commodities for Y profit". if the total is less than, or equal to, this number, then they will be listed individually.
Nicely done, Darkcyde13. I'm definitely incorporating this one into my own scripts (stealing this). :-)
While trading/mining, I often carry more than 1 commodity type. When landing at stations, EDDI reports the ships's cargo profits one at a time, when profits are available. In situations where I am mining/rare trading, etc, I can easily have in excess of 15 different commodities. Listening to the looped profit report can be tiresome.
It would be nice to have a variable threshold based on the ship's cargo commodity count. If the cargo commodity count exceeds the threshold, a summarized sum total of profits for the count of commodities message is responded: "You can sell n commodities here for a total profit of X credits" or similar.
I have not yet worked with Cottle, but it appears to support loops and variables. I tried fiddling with this myself, but with my unfamiliarity with the events and scripts and EDDI packages, I find myself at a disadvantage.
This applies to the Commodity Sale Check script.