Page 1 of 1
NFO - dynamic values for production callback
Posted: 06 Dec 2008 11:56
by andythenorth
I have been learning how to use the production callback for industries. I have static production values working. I can also (unrelated - but useful) set the industry window text depending on the amount of cargo waiting (var40 for first cargo).
Now I want to dynamically modify the production value for a cargo depending on other criteria.
Code: Select all
//pseudo
varaction 2 to check callbacks
if callback ID is 00 (think 00 is the production callback ID??)
varaction 2 to store value(s) in registers according to my criteria xyz
action 2 that is production callback (also terminates action 2 chain)
In this case, the criteria will be proximity to another industry. Following much help earlier, I can now check that just fine.
1. Is my pseudo code approach above sensible / efficient?
2. On my reading the
wiki page, production callback ID is 00. Is that right?
3. I believe I'll be able to work out how to push the values onto registers, but I am unsure of how to structure doing so. Presumably I'll need more varaction 2s to set the register values (i.e. I can't check ranges, set registers appropriately, and return all in one varaction 2)?
cheers,
Andy
Re: NFO - dynamic values for production callback
Posted: 06 Dec 2008 12:08
by DaleStan
1) Does it work? If it works, and if NFORenum doesn't pitch a hissyfit, then it is sensible.
2) Yes and no. The production callback is any value of 0C for which you do not want to provide a conventional callback result. The same way other object's graphics callbacks are any value of 0C for which you do not want to provide a callback result.
3) Sometimes you need more var2s, sometimes you don't.
Re: NFO - dynamic values for production callback
Posted: 06 Dec 2008 12:16
by michael blunck
andythenorth wrote:
[...]
3. I believe I'll be able to work out how to push the values onto registers, but I am unsure of how to structure doing so. Presumably I'll need more varaction 2s to set the register values (i.e. I can't check ranges, set registers appropriately, and return all in one varaction 2)?
Yes, o/c you can. And that´s the real power of advanced var action2.
Here´s an example (taken from one of my .nfos, not industry-related though):
Code: Select all
-1 * 0 02 04 03 81
7E 11 20 FF // subroutine: check northern tile
0A 1A 20 04 // shift 2 bits left (*4)
0E 1A 20 00 // store in reg 0
0F 7E 12 20 FF // subroutine: check southern tile
0C 7D 00 20 FF // OR with reg 0
0E 1A 20 00 // store in reg 0
0F 67 00 20 0F // get slope data (var67, bits 0..3)
0A 1A 20 10 // shift 4 bits left (*16)
0C 7D 00 00 FF // OR with reg 0
...
In this way, you´d be able to construct very "significant " CB return codes.
With regards to your Q1, I don´t seem to understand your question in full, sorry.
regards
Michael
Re: NFO - dynamic values for production callback
Posted: 06 Dec 2008 14:34
by frosch
To extent Dalestan's post: Never check the callback ID against zero. Always put the production callback into the "else" branch.
Note that there are several callbacks which are always active, and that it is very likely that somewhen new callbacks will be added, which are unknown to your grf.
I.e. you have to ensure that unknown callbacks fail (result in the production callback action2). Failing callbacks will always result in some default behaviour.
OTOH when you put a regular callback result in the "else" branch you will return that value for various callbacks, and your grf will at least break when new callbacks will be introduced.
Re: NFO - dynamic values for production callback
Posted: 09 Dec 2008 20:34
by andythenorth
Thanks for those replies - I've expanded my pseudo code.
Code: Select all
Var Action 2
Check distance to nearest industry of type n (using var 64)
If in range 0-10:
Store 64 00 in register 100h
Else:
Store 32 00 in register 100h
Return ID of CB of production callback
[...]
Action 2 for Production Callback
Uses values in register 100h
I am stumped as to the (edit) NFO syntax for the "if,else,return CB ID" structure above - or perhaps this is not the way to structure it?
An alternative way would be to branch to one of two different var action 2s when I check the distance, then have those var action 2s store different values in the register. However Michael's comment above has me hoping that it can all be done in one var action 2.
cheers,
Andy
Re: NFO - dynamic values for production callback
Posted: 09 Dec 2008 20:56
by DaleStan
Code: Select all
if (something) {
foo();
} else {
foo();
}
Re: NFO - dynamic values for production callback
Posted: 09 Dec 2008 21:03
by frosch
First, you cannot use register 0x100 in the production callback

Only 0x00 - 0xFF.
Well, yes, you could do that in a single advanced action2. Using the Comparison operators you could create something like
Code: Select all
accu = var64[...]; // Load var 64
accu = (accu < 10 ? 0 : (accu == 10 ? 1 : 2)); // Compare it with 10 and store 0 for "<", 1 for "==" and 2 for ">"
accu >>= 1; // Turn 0 and 1 into 0, and 2 into 1. I.e. 0 if var64 <= 10, and 1 if > 10
accu *= 32; // Multiply with 32
accu += 32; // Add 32
register[...] = accu; // store in some register for following production callback
But I guess you agree that using the usual varaction2 case is a lot easier
Small warning: When you do not need the varaction2 case, and always want to chain to the same action2, do not fall into that pit:
NewGrfSpecs wrote:Since 2.0.1 alpha 57, nvar=0 is a special case. Instead of using ranges, nvar=0 means that the result of an advanced calculation (or, if no calculation is performed, the adjusted variable value itself) is returned as callback result, with bit 15 set. This is useful for those callbacks where many different return values are possible and it is easier to calculate them than list them in ranges. The default value must still be specified, and will be used in case the variable(s) used are not available.
Re: NFO - dynamic values for production callback
Posted: 09 Dec 2008 21:06
by andythenorth
DaleStan wrote:Code: Select all
if (something) {
foo();
} else {
foo();
}
Ahem, thanks. A perfectly accurate answer, but doesn't much help. I should know better than to ask a bad question.
It's the specific NFO syntax that is tripping me up. I know the following is the wrong way to do it (nfo-renum agrees with me!), but I don't know what's right.
Code: Select all
9 * 35 02 0A 0E 81 // store production values in registers
64 01 00 FF // check variable 64, with industry type in first byte after variable
01 // check one range
0A 1A 20 64 00
0E 1A 20 00 01 // store 64 in register 01...
0A 00 00 05 // ...if distance is in range 0 - 5 (use a byte for each end of range)
0A 1A 20 32 00
0E 1A 20 00 01 // store 32 in register 01...
0A 00 // ...otherwise
(EDIT) @ Frosch - thanks, I'll try the multiple varaction 2 route.
cheers,
Andy
Re: NFO - dynamic values for production callback
Posted: 09 Dec 2008 21:15
by andythenorth
frosch wrote:But I guess you agree that using the usual varaction2 case is a lot easier

Hmm, I should do this properly using the registers, but would an alternative route to be to have two production callbacks, and simply chain to a different one depending on the value of variable 64?
Code: Select all
(Pseudo)
Define production callback A using 32 as production amount
Define production callback B using 64 as production amount
Check var 64
If in range 0..10, return production CB ID B
Else return production CB ID A
Seems more pragmatic for a simple case, but also like it could be a headache if production values are affected by multiple factors (needs lots of production callbacks defined). Modifying the current value of a register depending on each condition would seem better?
Also, defining two production callbacks seems inelegant (redundant code)?
Re: NFO - dynamic values for production callback
Posted: 09 Dec 2008 21:21
by frosch
Action2 do not need to be linked lineary, or like a tree. You can rejoin them:
Code: Select all
Action2 ID 00: Production callback, return production of register 0x99
Action2 ID 01: Store 30 in register 0x99, chain to ID 00
Action2 ID 02: Store 60 in register 0x99, chain to ID 00
Action2 ID 03: Test var 64, and chain to ID 01 or 02
Re: NFO - dynamic values for production callback
Posted: 09 Dec 2008 21:43
by andythenorth
frosch wrote:Action2 do not need to be linked lineary, or like a tree. You can rejoin them:
Code: Select all
Action2 ID 00: Production callback, return production of register 0x99
Action2 ID 01: Store 30 in register 0x99, chain to ID 00
Action2 ID 02: Store 60 in register 0x99, chain to ID 00
Action2 ID 03: Test var 64, and chain to ID 01 or 02
Yes, that's exactly the code I'm trying to write now.
I thought there might be an easier-to-code (but not so good) route, using the older version of production callback with the values hard-coded, instead of stored in registers. However I'd rather do it right.
Unfortunately nfo-renum finds the following errors in my code
Code: Select all
//!!Warning (86): Offset 8: Testing nonexistant variable 0E.
//!!Warning (42): Length does not match nvar of 00. (Expected 14 bytes)
//!!Error (55): 01 0F is neither callback nor cargo ID.
9 * 24 02 0A 0E // store production values in registers
81
1A 20 64 00
0E 1A 20 00 01 // store 64 in register 01 (!! I'm working out how to change this to register 0x99 !!)
0F
1C 00 FF // checking variable 1C because I can't use nvar=0 and therefore need to check something (right?)
01 // check one range
0A 00 00 00 // return CB 0A if variable is in range 0
0A 00 // otherwise return CB 0A (yes it looks redundant, but it's needed)
Re: NFO - dynamic values for production callback
Posted: 10 Dec 2008 04:53
by DaleStan
Well, start with the first one. NFORenum thinks the byte 0E at offset 8 (the ninth byte) is a variable. It is, as is usually the case, correct. That byte is supposed to specify a variable.
Try turning the beautifier on, and see what sort of formatting you get. Stripping the comments and setting linebreaks to 3 often helps generate more interesting formatting.
If that fails to provide sufficient clues, run through each byte, and specify which element of the action 2 it is. Find the byte that doesn't match up to an element, or the element that has too many bytes. Then remove/fix, as appropriate.
Oh, and don't use the entity <var-adjust>. Use its components -- <shift>, <and>, &c..
Re: NFO - dynamic values for production callback
Posted: 10 Dec 2008 10:10
by andythenorth
DaleStan wrote:Well, start with the first one. NFORenum thinks the byte 0E at offset 8 (the ninth byte) is a variable. It is, as is usually the case, correct[...helpful advice...]
Thanks DaleStan, that's helped. I have code that passes nfo-renum ok. I don't know that it's good code yet, but it's not fundamentally broken.
New problem: I may have misunderstood how the production callback works.
In my first case I have used it successfully for a processing industry. I used the production callback that is called every 256 ticks, and cargo is processed at the rate I expect.
I have a second case which is an extractive industry. I am again using the 256 tick production callback, and I had made the assumption that if I specify an amount for the first produced cargo type, that much cargo will be produced per tick. However this seems to not be the case so far. The industry accepts no cargoes. The action 2 defining the production callback passes nfo-renum, and I believe is correct.
Does the production callback allow for the production of cargo if none of the accepted cargoes are waiting to be processed? (I can imagine good reasons why it may not, but am hoping for a definitive answer!)
Would callback 35 (Monthly random production change) offer a better way to modify produced cargo amounts?
thanks,
Andy
Re: NFO - dynamic values for production callback
Posted: 10 Dec 2008 21:29
by frosch
NewGrfSpecs wrote:The total amount of cargo waiting cannot go negative. If you specify more than the amount actually waiting, the incoming amount will be zeroed instead.
Were you asking for that?
Re: NFO - dynamic values for production callback
Posted: 11 Dec 2008 08:23
by andythenorth
frosch wrote:NewGrfSpecs wrote:The total amount of cargo waiting cannot go negative. If you specify more than the amount actually waiting, the incoming amount will be zeroed instead.
Were you asking for that?
No sorry

It's the outgoing cargo I want to modify, e.g.
Code: Select all
Pseudo
cargo waiting: 0
amount to subtract from cargo waiting: 0
cargo produced: 64
I think either that's not supported by production callback...or my code is wrong?
Code: Select all
8 * 15 02 0A 0A // setup production callback
00 // callback version
00 00 // amount to subtract from first accepted cargo
00 00 // ...second accepted cargo
00 00 // ...third accepted cargo
01 00 // amount to add to first produced cargo
00 00 // ...second produced cargo
00
If production callback doesn't work that way, I need a workaround, which I think callback 35 will provide.
cheers,
Andy
Re: NFO - dynamic values for production callback
Posted: 11 Dec 2008 18:12
by frosch
Well, ... ...., and what does not work?
Your production callback should produce 1 piece of output cargo every time it is called (as long as you do not check other variables earlier). Every incoming cargo should be stockpiled for your grandchildren.
When you activated the 256 tick callback, it should produce about 8 or 9 pieces every month.
a) "It produces nothing": Maybe you did not activated the callback.
b) "It produces more a lot more than those 9 pieces": Property 12 or 13 is non zero. Their value (scaled by production level) is added to the result of the 256 tick production callback. I.e. the callback amount of 8 won't be noticed.
Re: NFO - dynamic values for production callback
Posted: 11 Dec 2008 19:22
by andythenorth
frosch wrote:Well, ... ...., and what does not work?
a) "It produces nothing": Maybe you did not activated the callback.
b) "It produces more a lot more than those 9 pieces"...
Thanks Frosch. It was neither a, nor b. It was coder error - I made a silly mistake elsewhere in the action 2. However, being told that it *should* work helped me look elsewhere for the error.
I think I prefer pushing pixels
