A possible extension:To support ecologically sound lumber mills, you may want to add a minimum number of trees that must be present before allowing cutting.
I've thought about harder per-tile conditions, too (which is what you propose). On the other hand, circular search will take longer to find an appropriate tile then. If the performance impact was significant would be something, one had to determine by profiling then.
I thought about this last night, and concluded your reasoning (dutch) "snijdt geen hout" (literally "does not cut wood", meaning "is not a good argument"). Basically, adding such conditions is equivalent to reducing the amount of forest around the mill, ie a player founding a mill in the middle of a desert (or, knowing Joe the Plumber, filling the entire desert with them).
Such an action should not bring down the application. As a result, reducing the chance of finding a 'good' site should also be allowed without bad performance effects.
I also thought about reducing computational effort. A weak point in the circular search is the fact that you start anew each time, especially for strategy 00. Maybe you can start a search from the last position you stopped the previous time instead (and 'wrap around' if necessary).
Another (much more complex) option may be to cache search results. Imagine laying out a grid of points every n tiles, where you only store points within reach of a search start-position. At each point you keep track of the minimal radius needed to find a cutting position (the global grid has the advantage that 2 lumbermills close to each other can benefit both from the same information).
After deciding your start search position, you get the minimal radius from the nearest point, and use that to decide on the minimal radius (taking the difference between both positions into account). After the search you update the point information (again taking the position-difference into account).
The tricky part of this scheme is how to reset the cached information. Ideally, a tree would warn the points ("he, I am fully grown now, please cut me"). Another approach is to do a wrap-around when a search from the minimal radius to the end doesn't give any result, and do the search from 0 to the minimal radius. If that gives a cutting position, the cached information was outdated.
The latter approach however does not prevent heavy search costs when there are no trees nearby (thus defeating the caching).
Anyway, glad to see that you added the condition in the definition (bits 3 and 4). For completeness, you could add to it that you currently do not use these bits.
Then about the numbers:
R is between 0 and 4*15=60.
After re-reading, I am a bit confused about the circular search length L. What is 'length' here? Another radius? a number of tiles? something else?
If length is another radius, I am very scared
of the total size. L is then between 0 and 15*8=120.
So total max area is 2*(60+120)=2*180=360 diameter. Strategy 00 is even more scary with 2*254=508 in diameter (I don't understand your 255=>40 mapping, but you probably have a good reason for it).
None the less, 2 of these babies at max range (1 with strategy 00) would kill all trees in my entire world (I normally play at 256x512).
If length is number of tiles searched, it is much better, max radius (Area=pi*r*r <=> r=sqrt(Area/pi)) would then be sqrt(120/3.14)=6.2 or sqrt(254/3.14)=8.9 for strategy 00 (default: sqrt(40/3.14)=3.6).
In this case, I think R is a bit unbalanced w.r.t. L.
Last but not least, maybe you want to introduce an offset somewhere, eg R=1 or L=1 does not seem very useful.
Edit: I've taken another look into the source code an there is something I find very illogical: No matter whether the special effect "cut trees" is set normal production is done first (i.e. production callback executed, produced cargo added to the waiting cargo), then the cutting of trees is done if appropriately (special flag set, callback allows to). If cutting trees succeeds another hardcoded 45 items are added to i->produced_cargo_waiting, i.e. the first cargo slot.
Ok, so I simply get more lumber if trees can be cut.
IMHO, it's inappropriate that custom production is always done no matter whether cutting trees succeeded and that the effect is hardcoded. In any case the production callback should be delayed until cutting has been tried.
The nice thing about the current implementation is that production doesn't drop to 0 due to lack of trees.
The easiest solution I can imagine is then to call the production callback only when cutting did succeed.
An even better solution would be to call the production callback always and make the result of cutting available to the production callback (I don't know if and how this is possible) and let it decide, what to do. However, I'm kind of lazy and I think the easy solution is good enough.
I agree with you that the industry should know about the cutting result.
I don't know whether it is allowed to simply not call an industry when cutting fails. At least it means you don't give it an option of deciding what to do in that situation (for example, you couldn't code a GRF file that duplicates current behaviour).
While thinking this over, I concluded that we may need another parameter, namely how often should we try cutting?
Your proposal rests on the idea that trees will grow fast enough to get some non-zero cutting ratio. For the game this is most likely some constant. Trees grow at some constant rate, and querying industry for production has a constant rate, thus our cutting speed is also constant.
As a result, for a sustainable production (in these environment-friendly times), there is some fixed minimal area that we need. Larger areas have no use (other than leaving more trees alive), and smaller area will ultimately kill the industry. On the other hand, if we can specify the rate of trying to cut, it is much easier to get different useful sizes.