-
-
Save nielsmh/0bb2555e75c6b2a65ebfefba08b4fd58 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
__license__ = """ | |
NML is free software; you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation; either version 2 of the License, or | |
(at your option) any later version. | |
NML is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License along | |
with NML; if not, write to the Free Software Foundation, Inc., | |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.""" | |
from nml.actions import action2, action2var, action6, actionD | |
from nml import expression, nmlop, global_constants | |
class Action2Production(action2.Action2): | |
""" | |
Class corresponding to Action2Industries (=production CB) | |
@ivar version: Production CB version. Version 0 uses constants, version 1 uses registers. | |
@type version: C{int} | |
@ivar sub_in: Amounts (v0) or registers (v1) to subtract from incoming cargos. | |
@type sub_in: C{list} of (C{int} or L{VarAction2Var}) | |
@ivar add_out: Amounts (v0) or registers (v1) to add to the output cargos. | |
@type add_out: C{list} of (C{int} or L{VarAction2Var}) | |
@ivar again: Number (v0) or register (v1), production CB will be run again if nonzero. | |
@type again C{int} or L{VarAction2Var} | |
""" | |
def __init__(self, name, pos, version, sub_in, add_out, again): | |
action2.Action2.__init__(self, 0x0A, name, pos) | |
self.version = version | |
if version in (0, 1): | |
self.sub_in = sub_in | |
assert len(self.sub_in) == 3 | |
self.add_out = add_out | |
assert len(self.add_out) == 2 | |
elif version == 2: | |
self.sub_in = sub_in | |
self.add_out = add_out | |
else: | |
assert False | |
self.again = again | |
def prepare_output(self, sprite_num): | |
action2.Action2.prepare_output(self, sprite_num) | |
def write(self, file): | |
if self.version in (0, 1): | |
cargo_size = 2 if self.version == 0 else 1 | |
size = 2 + 5 * cargo_size | |
action2.Action2.write_sprite_start(self, file, size) | |
file.print_bytex(self.version) | |
values = self.sub_in + self.add_out + [self.again] | |
# Read register numbers if needed | |
if self.version == 1: values = [val.parameter for val in values] | |
for val in values[:-1]: | |
file.print_varx(val, cargo_size) | |
file.print_bytex(values[-1]) | |
elif self.version == 2: | |
size = 4 + 2 * (len(self.sub_in) + len(self.add_out)) | |
action2.Action2.write_sprite_start(self, file, size) | |
file.print_bytex(self.version) | |
file.print_byte(len(self.sub_in)) | |
for cargoindex, value in self.sub_in: | |
file.print_bytex(cargoindex) | |
file.print_bytex(value.parameter) | |
file.print_byte(len(self.add_out)) | |
for cargoindex, value in self.add_out: | |
file.print_bytex(cargoindex) | |
file.print_bytex(value.parameter) | |
file.print_bytex(self.again.parameter) | |
file.newline() | |
file.end_sprite() | |
def resolve_prodcb_register(param, varact2parser): | |
if isinstance(param, expression.StorageOp) and param.name == 'LOAD_TEMP' and isinstance(param.register, expression.ConstantNumeric): | |
# We can load a register directly | |
res = action2var.VarAction2Var(0x7D, 0, 0xFFFFFFFF, param.register.value) | |
else: | |
if len(varact2parser.var_list) != 0: | |
varact2parser.var_list.append(nmlop.VAL2) | |
varact2parser.var_list_size += 1 | |
varact2parser.parse_expr(action2var.reduce_varaction2_expr(param, 0x0A)) | |
store_tmp = action2var.VarAction2StoreTempVar() | |
res = action2var.VarAction2LoadTempVar(store_tmp) | |
varact2parser.var_list.append(nmlop.STO_TMP) | |
varact2parser.var_list.append(store_tmp) | |
varact2parser.var_list_size += store_tmp.get_size() + 1 # Add 1 for operator | |
return res | |
def finish_production_actions(produce, prod_action, action_list, varact2parser): | |
action_list.append(prod_action) | |
if len(varact2parser.var_list) == 0: | |
produce.set_action2(prod_action, 0x0A) | |
else: | |
# Create intermediate varaction2 | |
varaction2 = action2var.Action2Var(0x0A, '{}@registers'.format(produce.name.value), produce.pos, 0x89) | |
varaction2.var_list = varact2parser.var_list | |
action_list.extend(varact2parser.extra_actions) | |
extra_act6 = action6.Action6() | |
for mod in varact2parser.mods: | |
extra_act6.modify_bytes(mod.param, mod.size, mod.offset + 4) | |
if len(extra_act6.modifications) > 0: action_list.append(extra_act6) | |
ref = expression.SpriteGroupRef(produce.name, [], None, prod_action) | |
varaction2.ranges.append(action2var.VarAction2Range(expression.ConstantNumeric(0), expression.ConstantNumeric(0), ref, '')) | |
varaction2.default_result = ref | |
varaction2.default_comment = '' | |
# Add two references (default + range) | |
action2.add_ref(ref, varaction2) | |
action2.add_ref(ref, varaction2) | |
produce.set_action2(varaction2, 0x0A) | |
action_list.append(varaction2) | |
action6.free_parameters.restore() | |
return action_list | |
def get_production_actions(produce): | |
""" | |
Get the action list that implements the given produce-block in nfo. | |
@param produce: Produce-block to parse. | |
@type produce: L{Produce} | |
""" | |
action_list = [] | |
act6 = action6.Action6() | |
action6.free_parameters.save() | |
result_list = [] | |
varact2parser = action2var.Varaction2Parser(0x0A) | |
if all(x.supported_by_actionD(False) for x in produce.param_list): | |
version = 0 | |
offset = 4 | |
for i, param in enumerate(produce.param_list): | |
result, offset = actionD.write_action_value(param, action_list, act6, offset, 2 if i < 5 else 1) | |
result_list.append(result.value) | |
else: | |
version = 1 | |
for i, param in enumerate(produce.param_list): | |
result_list.append(resolve_prodcb_register(param, varact2parser)) | |
if len(act6.modifications) > 0: action_list.append(act6) | |
prod_action = Action2Production(produce.name.value, produce.pos, version, result_list[0:3], result_list[3:5], result_list[5]) | |
return finish_production_actions(produce, prod_action, action_list, varact2parser) | |
def get_production_v2_actions(produce): | |
""" | |
Get the action list that implements the given produce-block in nfo. | |
@param produce: Produce-block to parse. | |
@type produce: L{Produce2} | |
""" | |
action_list = [] | |
act6 = action6.Action6() | |
action6.free_parameters.save() | |
result_list = [] | |
varact2parser = action2var.Varaction2Parser(0x0A) | |
def resolve_cargoitem(item): | |
cargolabel = item.name.value | |
if cargolabel not in global_constants.cargo_numbers: | |
raise generic.ScriptError("Cargo label {0} not found in your cargo table".format(cargolabel), pos) | |
cargoindex = global_constants.cargo_numbers[cargolabel] | |
valueregister = resolve_prodcb_register(item.value, varact2parser) | |
return (cargoindex, valueregister) | |
sub_in = [resolve_cargoitem(item) for item in produce.subtract_in] | |
add_out = [resolve_cargoitem(item) for item in produce.add_out] | |
again = resolve_prodcb_register(produce.again, varact2parser) | |
prod_action = Action2Production(produce.name.value, produce.pos, 2, sub_in, add_out, again) | |
return finish_production_actions(produce, prod_action, action_list, varact2parser) | |
def make_empty_production_action2(pos): | |
""" | |
Make an empty production action2 | |
For use with failed callbacks | |
@param pos: Positional context. | |
@type pos: L{Position} | |
@return: The created production action2 | |
@rtype: L{Action2Production} | |
""" | |
return Action2Production("@CB_FAILED_PROD", pos, 0, [0, 0, 0], [0, 0], 0) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Automatically generated by GRFCODEC. Do not modify! | |
// (Info version 32) | |
// Escapes: 2+ 2- 2< 2> 2u< 2u> 2/ 2% 2u/ 2u% 2* 2& 2| 2^ 2sto = 2s 2rst = 2r 2psto 2ror = 2rot 2cmp 2ucmp 2<< 2u>> 2>> | |
// Escapes: 71 70 7= 7! 7< 7> 7G 7g 7gG 7GG 7gg 7c 7C | |
// Escapes: D= = DR D+ = DF D- = DC Du* = DM D* = DnF Du<< = DnC D<< = DO D& D| Du/ D/ Du% D% | |
// Format: spritenum imagefile depth xpos ypos xsize ysize xrel yrel zoom flags | |
0 * 4 \d18 | |
1 * 54 14 "C" "INFO" | |
"B" "VRSN" \w4 \dx00000000 | |
"B" "MINV" \w4 \dx00000000 | |
"B" "NPAR" \w1 00 | |
"B" "PALS" \w1 "A" | |
"B" "BLTR" \w1 "8" | |
00 | |
00 | |
2 * 165 08 08 "NML\04" "NML Example NewGRF: Industry" 00 "\8ENML Example NewGRF: Industry\0D\98This NewGRF is intended to provide a coding example for the high-level NewGRF-coding language NML." 00 | |
3 * 110 04 00 FF 01 \wxD000 "\0DVar 69: \90Foo \0D\98Var 6A: \90Foo \0D\98Var 6B: \90Foo \0D\98Var 6C: \90Foo \0D\98Var 6D: \90Foo \0D\98Var 6E: \90Foo \0D\98Var 6F: \90Foo" 00 | |
4 * 52 00 08 \b1 0B FF \wx0000 | |
09 "PASS" "COAL" "MAIL" "OIL_" "LVST" | |
"GOOD" "GRAI" "WOOD" "IORE" "STEL" | |
"VALU" | |
// Name: test_produce1 | |
5 * 13 02 0A FF 02 \b2 01 80 08 81 \b1 09 82 83 | |
// Name: test_produce1@registers | |
6 * 72 02 0A FF 89 | |
1A 20 \dx00000005 | |
\2sto 1A 20 \dx00000080 | |
\2r 1A 20 \dx00000007 | |
\2sto 1A 20 \dx00000081 | |
\2r 1A 20 \dx00000005 | |
\2sto 1A 20 \dx00000082 | |
\2r 1A 20 \dx00000001 | |
\2sto 1A 00 \dx00000083 | |
\b1 | |
\wx00FF \dx00000000 \dx00000000 | |
\wx00FF // | |
7 * 64 00 0A \b6 01 FF \wx0000 | |
08 06 | |
09 06 | |
25 \b4 | |
02 05 09 0A | |
26 \b4 | |
01 03 08 06 | |
27 \b4 | |
00 00 00 00 | |
28 \b4 \b4 | |
\wx0100 \wx0100 \wx0100 \wx0100 | |
\wx0000 \wx0000 \wx0000 \wx0000 | |
\wx0000 \wx0000 \wx0400 \wx0000 | |
\wx0080 \wx0000 \wx0000 \wx0080 | |
8 * 11 00 0A \b2 01 FF \wx0000 | |
21 02 | |
22 01 | |
// Name: @CB_FAILED_PROD | |
9 * 15 02 0A FE 00 \wx0000 \wx0000 \wx0000 \wx0000 \wx0000 00 | |
// Name: @CB_FAILED0A | |
10 * 23 02 0A FE 89 | |
0C 00 \dx0000FFFF | |
\b1 | |
\wx8000 \dx00000000 \dx00000000 // graphics callback -> return 0 | |
\wx00FE // Non-graphics callback, return graphics result | |
// Name: @action3_0 | |
11 * 23 02 0A FF 89 | |
18 00 \dx000000FF | |
\b1 | |
\wx00FF \dx00000000 \dx00000000 // test_produce1; | |
\wx00FE // @CB_FAILED0A; | |
// Name: @action3_1 | |
12 * 33 02 0A FE 89 | |
0C 00 \dx0000FFFF | |
\b2 | |
\wx00FF \dx00000000 \dx00000000 // @action3_0; | |
\wx8000 \dx0000003A \dx0000003A // return string(STR_INDUSTRY_EXTRA_TEXT); | |
\wx00FE // @CB_FAILED0A; | |
13 * 7 03 0A 01 00 \b0 | |
\wx00FE // @action3_1; | |
14 * 13 00 09 \b3 01 FF \wx0000 | |
08 27 | |
09 27 | |
12 02 | |
15 * 13 00 09 \b3 01 FF \wx0001 | |
08 28 | |
09 28 | |
12 02 | |
16 * 13 00 09 \b3 01 FF \wx0002 | |
08 29 | |
09 29 | |
12 02 | |
17 * 13 00 09 \b3 01 FF \wx0003 | |
08 2A | |
09 2A | |
12 02 | |
18 * 26 00 0A \b6 01 FF \wx0001 | |
08 09 | |
09 09 | |
25 \b3 | |
04 06 07 | |
26 \b0 | |
27 \b3 | |
08 0C 04 | |
28 \b0 \b0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This file is aimed to provide an example on how to code a basic industry in NML. | |
* To keep the code readable, not every property or variable is documented in | |
* detail, refer to the object-specific reference in the documentation. | |
* | |
* This version shows only how to modify a built-in industry. | |
* | |
* Apart from this file, you will also need the following | |
* - Language files, to be placed in the 'lang' folder. | |
* Currently english.lng is supplied. | |
*/ | |
/********************************************** | |
* Header, containing some general stuff: | |
**********************************************/ | |
/* | |
* First, define a grf block. This defines some basic properties of the grf, | |
* which are required for the grf to be valid and loadable. | |
*/ | |
grf { | |
/* This grf is part of NML, therefore "NML" is chosen as the first three | |
* characters of the GRFID. It is the third real grf defined as part of | |
* NML, therefore the last character is set to 2. Successive grfs will | |
* have 3, 4, etc. there, to make sure each example grf has a unique GRFID. | |
*/ | |
grfid : "NML\04"; | |
name : string(STR_GRF_NAME); | |
desc : string(STR_GRF_DESCRIPTION); | |
version : 0; // must be numeric | |
min_compatible_version : 0; | |
} | |
/* this example assumes we're just matching to the default temperate cargos, this wouldn't be the usual case */ | |
cargotable { | |
PASS, COAL, MAIL, OIL_, LVST, GOOD, GRAI, WOOD, IORE, STEL, VALU | |
} | |
produce(test_produce1, [COAL: 5; IORE: 7;], [STEL: 5;], 1) | |
produce(test_produce2, [COAL: 5; IORE: 7;], [STEL: 5;]) | |
produce(test_produce3, [], [], 0) | |
/* | |
* This example extends the cargos accepted and produce by the default temperate factory. | |
*/ | |
item(FEAT_INDUSTRIES, factory) { | |
property { | |
substitute: INDUSTRYTYPE_TEMPERATE_FACTORY; | |
override: INDUSTRYTYPE_TEMPERATE_FACTORY; | |
cargo_types: [ | |
accept_cargo("COAL", produce_cargo("MAIL", 1), produce_cargo("GOOD", 1), produce_cargo("STEL", 1), produce_cargo("VALU", 1)), | |
accept_cargo("OIL_"), | |
accept_cargo("IORE", produce_cargo("STEL", 4)), | |
accept_cargo("GRAI", produce_cargo("MAIL", 0.5), produce_cargo("VALU", 0.5)) | |
]; | |
} | |
graphics { | |
extra_text_industry: string(STR_INDUSTRY_EXTRA_TEXT); | |
produce_cargo_arrival: test_produce1; | |
} | |
} | |
item(FEAT_INDUSTRYTILES, factory_tile_1) { | |
property { | |
substitute: 39; | |
override: 39; | |
special_flags: bitmask(INDTILE_FLAG_ACCEPT_ALL); | |
} | |
} | |
item(FEAT_INDUSTRYTILES, factory_tile_2) { | |
property { | |
substitute: 40; | |
override: 40; | |
special_flags: bitmask(INDTILE_FLAG_ACCEPT_ALL); | |
} | |
} | |
item(FEAT_INDUSTRYTILES, factory_tile_3) { | |
property { | |
substitute: 41; | |
override: 41; | |
special_flags: bitmask(INDTILE_FLAG_ACCEPT_ALL); | |
} | |
} | |
item(FEAT_INDUSTRYTILES, factory_tile_4) { | |
property { | |
substitute: 42; | |
override: 42; | |
special_flags: bitmask(INDTILE_FLAG_ACCEPT_ALL); | |
} | |
} | |
/* | |
* This example causes the default farm to produce livestock, grain, and wood. | |
*/ | |
item(FEAT_INDUSTRIES, farm) { | |
property { | |
substitute: INDUSTRYTYPE_TEMPERATE_ARCTIC_FARM; | |
override: INDUSTRYTYPE_TEMPERATE_ARCTIC_FARM; | |
cargo_types: [ | |
produce_cargo("LVST", 8), | |
produce_cargo("GRAI", 12), | |
produce_cargo("WOOD", 4), | |
]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment