15
15
16
16
import itertools
17
17
18
- from nml import generic , nmlop , global_constants
18
+ from nml import generic , grfstrings , nmlop , global_constants
19
19
from nml .expression import (
20
20
AcceptCargo ,
21
21
Array ,
@@ -170,7 +170,7 @@ def get_size(self):
170
170
#
171
171
# 'required' (value doesn't matter) if the property is required for the item to be valid.
172
172
173
- properties = 0x15 * [None ]
173
+ properties = 0x16 * [None ]
174
174
175
175
#
176
176
# Some helper functions that are used for multiple features
@@ -305,22 +305,18 @@ class VariableListProp(BaseAction0Property):
305
305
Property value that is a variable-length list of variable sized values, the list length is written before the data.
306
306
"""
307
307
308
- def __init__ (self , prop_num , data , size , extended ):
308
+ def __init__ (self , prop_num , data , size , size_size ):
309
309
# data is a list, each element belongs to an item ID
310
310
# Each element in the list is a list of cargo types
311
311
self .prop_num = prop_num
312
312
self .data = data
313
313
self .size = size
314
- self .extended = extended
314
+ self .size_size = size_size
315
315
316
316
def write (self , file ):
317
317
file .print_bytex (self .prop_num )
318
318
for elem in self .data :
319
- if self .extended :
320
- file .print_bytex (0xFF )
321
- file .print_word (len (elem ))
322
- else :
323
- file .print_byte (len (elem ))
319
+ file .print_varx (len (elem ), self .size_size )
324
320
for i , val in enumerate (elem ):
325
321
if i % 8 == 0 :
326
322
file .newline ()
@@ -330,13 +326,31 @@ def write(self, file):
330
326
def get_size (self ):
331
327
total_len = 1 # Prop number
332
328
for elem in self .data :
333
- # For each item ID to set, make space for all values + 3 or 1 for the length
334
- total_len += len (elem ) * self .size + ( 3 if self .extended else 1 )
329
+ # For each item ID to set, make space for all values + size_size for the length
330
+ total_len += len (elem ) * self .size + self .size_size
335
331
return total_len
336
332
337
333
338
- def VariableByteListProp (prop_num , data , extended = False ):
339
- return VariableListProp (prop_num , data , 1 , extended )
334
+ class StringProp (BaseAction0Property ):
335
+ """
336
+ Property value that is zero-terminated string.
337
+ """
338
+
339
+ def __init__ (self , prop_num , string ):
340
+ self .prop_num = prop_num
341
+ self .string = string
342
+
343
+ def write (self , file ):
344
+ file .print_bytex (self .prop_num )
345
+ file .print_string (self .string .value , True , True )
346
+ file .newline ()
347
+
348
+ def get_size (self ):
349
+ return grfstrings .get_string_size (self .string .value ) + 1
350
+
351
+
352
+ def VariableByteListProp (prop_num , data , size_size = 1 ):
353
+ return VariableListProp (prop_num , data , 1 , size_size )
340
354
341
355
342
356
def ctt_list (prop_num , * values ):
@@ -353,8 +367,40 @@ def ctt_list(prop_num, *values):
353
367
]
354
368
355
369
356
- def VariableWordListProp (num_prop , data , extended = False ):
357
- return VariableListProp (num_prop , data , 2 , extended )
370
+ def VariableWordListProp (num_prop , data , size_size = 1 ):
371
+ return VariableListProp (num_prop , data , 2 , size_size )
372
+
373
+
374
+ def badge_list (prop_num , * values ):
375
+ # values may have multiple entries, if more than one item ID is set (e.g. multitile houses)
376
+ # Each value is an expression.Array of cargo types
377
+
378
+ table = global_constants .badge_numbers
379
+
380
+ for value in values :
381
+ if not isinstance (value , Array ):
382
+ raise generic .ScriptError ("Value of badgelist property must be an array" , value .pos )
383
+
384
+ for badge in value .values :
385
+ if not isinstance (badge , StringLiteral ) or badge .value not in table :
386
+ raise generic .ScriptError (
387
+ "Parameter for badges must be a string literal that is also in your badge table"
388
+ )
389
+
390
+ return [
391
+ VariableListProp (
392
+ prop_num ,
393
+ [[table [badge .value ] for badge in single_item_array .values ] for single_item_array in values ],
394
+ 2 ,
395
+ 2 ,
396
+ )
397
+ ]
398
+
399
+
400
+ def string_property (prop_num , value ):
401
+ if not isinstance (value , StringLiteral ):
402
+ raise generic .ScriptError ("Value of label property must be a StringLiteral" , value .pos )
403
+ return [StringProp (prop_num , value )]
358
404
359
405
360
406
def accepted_cargos (prop_num , * values ):
@@ -478,6 +524,7 @@ def prop_test(value):
478
524
"curve_speed_mod" : {"size" : 2 , "num" : 0x2E , "unit_conversion" : 256 },
479
525
"variant_group" : {"size" : 2 , "num" : 0x2F },
480
526
"extra_flags" : {"size" : 4 , "num" : 0x30 },
527
+ "badges" : {"custom_function" : lambda value : badge_list (0x33 , value )},
481
528
}
482
529
# fmt: on
483
530
@@ -556,6 +603,7 @@ def prop15_test(value):
556
603
],
557
604
"variant_group" : {"size" : 2 , "num" : 0x26 },
558
605
"extra_flags" : {"size" : 4 , "num" : 0x27 },
606
+ "badges" : {"custom_function" : lambda value : badge_list (0x2A , value )},
559
607
}
560
608
# fmt: on
561
609
@@ -646,6 +694,7 @@ def prop23_test(value):
646
694
"variant_group" : {"size" : 2 , "num" : 0x20 },
647
695
"extra_flags" : {"size" : 4 , "num" : 0x21 },
648
696
"acceleration" : {"size" : 1 , "num" : 0x24 },
697
+ "badges" : {"custom_function" : lambda value : badge_list (0x26 , value )},
649
698
}
650
699
# fmt: on
651
700
@@ -707,6 +756,7 @@ def aircraft_is_large(value):
707
756
"range" : {"size" : 2 , "num" : 0x1F },
708
757
"variant_group" : {"size" : 2 , "num" : 0x20 },
709
758
"extra_flags" : {"size" : 4 , "num" : 0x21 },
759
+ "badges" : {"custom_function" : lambda value : badge_list (0x24 , value )},
710
760
}
711
761
# fmt: on
712
762
@@ -799,7 +849,7 @@ def station_tile_flags(value):
799
849
if not isinstance (value , Array ) or len (value .values ) % 2 != 0 :
800
850
raise generic .ScriptError ("Flag list must be an array of even length" , value .pos )
801
851
if len (value .values ) > 8 :
802
- return [VariableByteListProp (0x1E , [[flags .reduce_constant ().value for flags in value .values ]], True )]
852
+ return [VariableByteListProp (0x1E , [[flags .reduce_constant ().value for flags in value .values ]], 3 )]
803
853
pylons = 0
804
854
wires = 0
805
855
blocked = 0
@@ -843,6 +893,7 @@ def station_tile_flags(value):
843
893
"name" : {"size" : 2 , "num" : (256 , - 1 , 0x1C ), "string" : (256 , 0xC5 , 0xDC ), "required" : True },
844
894
"classname" : {"size" : 2 , "num" : (256 , - 1 , 0x1D ), "string" : (256 , 0xC4 , 0xDC )},
845
895
"tile_flags" : {"custom_function" : station_tile_flags }, # = prop 1E
896
+ "badges" : {"custom_function" : lambda value : badge_list (0x1F , value )},
846
897
}
847
898
# fmt: on
848
899
@@ -1051,6 +1102,7 @@ def mt_house_class(value, num_ids, size_bit):
1051
1102
"multitile_function" : mt_house_same ,
1052
1103
"custom_function" : lambda * values : accepted_cargos (0x23 , * values ),
1053
1104
},
1105
+ "badges" : {"custom_function" : lambda value : badge_list (0x24 , value )},
1054
1106
}
1055
1107
# fmt: on
1056
1108
@@ -1072,6 +1124,7 @@ def mt_house_class(value, num_ids, size_bit):
1072
1124
"animation_triggers" : {"size" : 1 , "num" : 0x11 },
1073
1125
"special_flags" : {"size" : 1 , "num" : 0x12 },
1074
1126
"accepted_cargos" : {"custom_function" : lambda value : accepted_cargos (0x13 , value )},
1127
+ "badges" : {"custom_function" : lambda value : badge_list (0x14 , value )},
1075
1128
}
1076
1129
# fmt: on
1077
1130
@@ -1344,6 +1397,7 @@ def check_accept(acp):
1344
1397
"nearby_station_name" : {"size" : 2 , "num" : 0x24 , "string" : 0xDC },
1345
1398
# prop 25+26+27+28 combined in one structure
1346
1399
"cargo_types" : {"custom_function" : industry_cargo_types },
1400
+ "badges" : {"custom_function" : lambda value : badge_list (0x29 , value )},
1347
1401
}
1348
1402
# fmt: on
1349
1403
@@ -1447,6 +1501,7 @@ def airport_layouts(value):
1447
1501
"noise_level" : {"size" : 1 , "num" : 0x0F },
1448
1502
"name" : {"size" : 2 , "num" : 0x10 , "string" : 0xDC },
1449
1503
"maintenance_cost" : {"size" : 2 , "num" : 0x11 },
1504
+ "badges" : {"custom_function" : lambda value : badge_list (0x12 , value )},
1450
1505
}
1451
1506
# fmt: on
1452
1507
@@ -1487,6 +1542,7 @@ def object_size(value):
1487
1542
"height" : {"size" : 1 , "num" : 0x16 },
1488
1543
"num_views" : {"size" : 1 , "num" : 0x17 },
1489
1544
"count_per_map256" : {"size" : 1 , "num" : 0x18 },
1545
+ "badges" : {"custom_function" : lambda value : badge_list (0x19 , value )},
1490
1546
}
1491
1547
# fmt: on
1492
1548
@@ -1533,6 +1589,7 @@ def label_list(value, prop_num, description):
1533
1589
"sort_order" : {"size" : 1 , "num" : 0x1A },
1534
1590
"name" : {"size" : 2 , "num" : 0x1B , "string" : 0xDC },
1535
1591
"maintenance_cost" : {"size" : 2 , "num" : 0x1C },
1592
+ "badges" : {"custom_function" : lambda value : badge_list (0x1E , value )},
1536
1593
}
1537
1594
1538
1595
#
@@ -1571,6 +1628,7 @@ def label_list(value, prop_num, description):
1571
1628
"animation_info" : {"size" : 2 , "num" : 0x0F , "value_function" : animation_info },
1572
1629
"animation_speed" : {"size" : 1 , "num" : 0x10 },
1573
1630
"animation_triggers" : {"size" : 1 , "num" : 0x11 },
1631
+ "badges" : {"custom_function" : lambda value : badge_list (0x12 , value )},
1574
1632
}
1575
1633
1576
1634
#
@@ -1657,4 +1715,14 @@ def byte_sequence_list(value, prop_num, description, expected_count):
1657
1715
# 11 (callback flags) is not set by user
1658
1716
"general_flags" : {"size" : 4 , "num" : 0x12 },
1659
1717
"cost_multipliers" : {"custom_function" : lambda x : byte_sequence_list (x , 0x15 , "Cost multipliers" , 2 )},
1718
+ "badges" : {"custom_function" : lambda value : badge_list (0x16 , value )},
1719
+ }
1720
+
1721
+ #
1722
+ # Feature 0x15 (Badges)
1723
+ #
1724
+
1725
+ properties [0x15 ] = {
1726
+ 'label' : {'custom_function' : lambda x : string_property (0x08 , x ), "required" : True },
1727
+ 'flags' : {'size' : 4 , 'num' : 0x09 },
1660
1728
}
0 commit comments