NFO - dynamic values for production callback

Discuss, get help with, or post new graphics for TTDPatch and OpenTTD, using the NewGRF system, here. Graphics for plain TTD also acceptable here.

Moderator: Graphics Moderators

Post Reply
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5705
Joined: 31 Mar 2007 14:23
Location: Lost in Music

NFO - dynamic values for production callback

Post 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
DaleStan
TTDPatch Developer
TTDPatch Developer
Posts: 10285
Joined: 18 Feb 2004 03:06
Contact:

Re: NFO - dynamic values for production callback

Post 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.
To get a good answer, ask a Smart Question. Similarly, if you want a bug fixed, write a Useful Bug Report. No TTDPatch crashlog? Then follow directions.
Projects: NFORenum (download) | PlaneSet (Website) | grfcodec (download) | grfdebug.log parser
michael blunck
Tycoon
Tycoon
Posts: 5954
Joined: 27 Apr 2005 07:09
Contact:

Re: NFO - dynamic values for production callback

Post 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
Image
frosch
OpenTTD Developer
OpenTTD Developer
Posts: 991
Joined: 20 Dec 2006 13:31
Location: Aschaffenburg

Re: NFO - dynamic values for production callback

Post 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.
⢇⡸⢸⠢⡇⡇⢎⡁⢎⡱⢸⡱⢸⣭⠀⢸⢜⢸⢸⣀⢸⣀⢸⣭⢸⡱⠀⢰⠭⡆⣫⠰⣉⢸⢸⠀⢰⠭⡆⡯⡆⢹⠁⠀⢐⠰⡁
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5705
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: NFO - dynamic values for production callback

Post 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
Last edited by andythenorth on 09 Dec 2008 20:57, edited 1 time in total.
DaleStan
TTDPatch Developer
TTDPatch Developer
Posts: 10285
Joined: 18 Feb 2004 03:06
Contact:

Re: NFO - dynamic values for production callback

Post by DaleStan »

Code: Select all

if (something) {
    foo();
} else {
    foo();
}
To get a good answer, ask a Smart Question. Similarly, if you want a bug fixed, write a Useful Bug Report. No TTDPatch crashlog? Then follow directions.
Projects: NFORenum (download) | PlaneSet (Website) | grfcodec (download) | grfdebug.log parser
frosch
OpenTTD Developer
OpenTTD Developer
Posts: 991
Joined: 20 Dec 2006 13:31
Location: Aschaffenburg

Re: NFO - dynamic values for production callback

Post 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.
⢇⡸⢸⠢⡇⡇⢎⡁⢎⡱⢸⡱⢸⣭⠀⢸⢜⢸⢸⣀⢸⣀⢸⣭⢸⡱⠀⢰⠭⡆⣫⠰⣉⢸⢸⠀⢰⠭⡆⡯⡆⢹⠁⠀⢐⠰⡁
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5705
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: NFO - dynamic values for production callback

Post 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. :wink:

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. :oops:

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
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5705
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: NFO - dynamic values for production callback

Post 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)?
frosch
OpenTTD Developer
OpenTTD Developer
Posts: 991
Joined: 20 Dec 2006 13:31
Location: Aschaffenburg

Re: NFO - dynamic values for production callback

Post 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
⢇⡸⢸⠢⡇⡇⢎⡁⢎⡱⢸⡱⢸⣭⠀⢸⢜⢸⢸⣀⢸⣀⢸⣭⢸⡱⠀⢰⠭⡆⣫⠰⣉⢸⢸⠀⢰⠭⡆⡯⡆⢹⠁⠀⢐⠰⡁
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5705
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: NFO - dynamic values for production callback

Post 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)
DaleStan
TTDPatch Developer
TTDPatch Developer
Posts: 10285
Joined: 18 Feb 2004 03:06
Contact:

Re: NFO - dynamic values for production callback

Post 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..
To get a good answer, ask a Smart Question. Similarly, if you want a bug fixed, write a Useful Bug Report. No TTDPatch crashlog? Then follow directions.
Projects: NFORenum (download) | PlaneSet (Website) | grfcodec (download) | grfdebug.log parser
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5705
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: NFO - dynamic values for production callback

Post 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
frosch
OpenTTD Developer
OpenTTD Developer
Posts: 991
Joined: 20 Dec 2006 13:31
Location: Aschaffenburg

Re: NFO - dynamic values for production callback

Post 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?
⢇⡸⢸⠢⡇⡇⢎⡁⢎⡱⢸⡱⢸⣭⠀⢸⢜⢸⢸⣀⢸⣀⢸⣭⢸⡱⠀⢰⠭⡆⣫⠰⣉⢸⢸⠀⢰⠭⡆⡯⡆⢹⠁⠀⢐⠰⡁
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5705
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: NFO - dynamic values for production callback

Post 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
frosch
OpenTTD Developer
OpenTTD Developer
Posts: 991
Joined: 20 Dec 2006 13:31
Location: Aschaffenburg

Re: NFO - dynamic values for production callback

Post 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.
⢇⡸⢸⠢⡇⡇⢎⡁⢎⡱⢸⡱⢸⣭⠀⢸⢜⢸⢸⣀⢸⣀⢸⣭⢸⡱⠀⢰⠭⡆⣫⠰⣉⢸⢸⠀⢰⠭⡆⡯⡆⢹⠁⠀⢐⠰⡁
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5705
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: NFO - dynamic values for production callback

Post 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 :)
Post Reply

Return to “Graphics Development”

Who is online

Users browsing this forum: Majestic-12 [Bot] and 6 guests