Updated for v2.01 of the MMP eASLRB.

master
Pacman Ghost 2 years ago
parent 851d6e94cb
commit 87ba93773e
  1. 6
      asl_rulebook2/bin/fixup_mmp_pdf.py
  2. 144
      asl_rulebook2/extract/content.py
  3. 6
      asl_rulebook2/extract/data/chapter-fixups.json
  4. 85
      asl_rulebook2/extract/data/footnote-fixups.json
  5. 7
      asl_rulebook2/extract/data/index-fixups.json
  6. 103
      asl_rulebook2/extract/data/target-fixups.json
  7. 330
      asl_rulebook2/extract/data/vo-note-fixups.json
  8. 2
      asl_rulebook2/extract/index.py
  9. 4
      asl_rulebook2/pdf.py
  10. 2
      asl_rulebook2/webapp/static/prepare.js

@ -91,6 +91,12 @@ def fixup_mmp_pdf( fname, output_fname, fix_zoom, optimize_web, rotate, log=None
annot.Dest = make_page_destination( pdf, page_no, "XYZ", top=page_height ) annot.Dest = make_page_destination( pdf, page_no, "XYZ", top=page_height )
log_msg( None, "" ) log_msg( None, "" )
# FUDGE! v2.01 of the MMP eASLRB PDF had a bodgy p104 (A62) that is a little wider than
# the rest of the pages (dumping the page dimensions using pikepdf didn't show anything unusual,
# but it was rendering differently in Firefox :-/), which was causing the h-scrollbar to appear.
# We hack the page width here to bring it in line with the others.
pdf.pages[ 104-1 ].MediaBox = [ 0, 0, 565, 792 ]
# save the updated PDF # save the updated PDF
log_msg( "progress", "Saving the fixed-up PDF..." ) log_msg( "progress", "Saving the fixed-up PDF..." )
# NOTE: Setting a blank password will encrypt the file, but doesn't require the user # NOTE: Setting a blank password will encrypt the file, but doesn't require the user

@ -22,25 +22,36 @@ from asl_rulebook2.utils import parse_page_numbers, fixup_text, append_text, rem
_DISABLE_SORT_ITEMS = [ _DISABLE_SORT_ITEMS = [
"B40", # nb: to detect B31.1 NARROW STREET "B40", # nb: to detect B31.1 NARROW STREET
"A16", "A16",
"A54", "A55", "A56",
"A58","A59","A60", # Chapter A footnotes (nb: page A61 is a mess wrt element order :-/) "A58","A59","A60", # Chapter A footnotes (nb: page A61 is a mess wrt element order :-/)
"B1", "B1",
"B45", "B46", # Chapter B footnotes "B45", "B46", # Chapter B footnotes
"C25", "C26", # Chapter C footnotes "C25", "C26", # Chapter C footnotes
"D27", # Chapter D footnotes "D27", # Chapter D footnotes
"E28", "E29", "E30", # Chapter E footnotes "E28", "E29", "E30", # Chapter E footnotes
"F20", "F21", # Chapter F footnotes "F2", "F6", "F7", "F8", "F9", "F10", "F11", "F16", "F17",
"F18", "F19", # Chapter F footnotes
"G48", "G49", "G50", # Chapter G footnotes "G48", "G49", "G50", # Chapter G footnotes
"H9", # Chapter H footnotes "H9", # Chapter H footnotes
429,431,432,433,434,435, # Italian vehicle notes # Chapter H vehicles/ordnace:
436,437,438,439, # Italian ordnance notes 359, 360,
363, 374,
376, 383, 387, 388, 390, 393,
408, 417, 426, 429,
434, 436, 438,
449, 452, 453,
467, 468, 469,
486, 492,
529, 530, 531, 532,
547, 549, 589,
] ]
_DEFAULT_ARGS = { _DEFAULT_ARGS = {
"chapter-a": "42-102", "chapter-b": "109-154", "chapter-c": "158-183", "chapter-d": "187-213", "chapter-a": "43-104", "chapter-b": "111-156", "chapter-c": "161-186", "chapter-d": "191-217",
"chapter-e": "216-245", "chapter-f": "247-267", "chapter-g": "270-319", "chapter-h": "322-324,326-330", "chapter-e": "221-250", "chapter-f": "253-271", "chapter-g": "275-324", "chapter-h": "327-329,331-335",
"chapter-j": "593", "chapter-j": "599",
"chapter-w": "647-664", "chapter-w": "653-670",
"content_vp_left": 0, "content_vp_right": 565, "content_vp_top": 715, "content_vp_bottom": 28, # viewport "content_vp_left": 0, "content_vp_right": 600, "content_vp_top": 715, "content_vp_bottom": 28, # viewport
"disable-sort-items": ",".join( str(si) for si in _DISABLE_SORT_ITEMS ) "disable-sort-items": ",".join( str(si) for si in _DISABLE_SORT_ITEMS )
} }
@ -48,35 +59,35 @@ _DEFAULT_ARGS = {
# - the order of the nationality + V/O types # - the order of the nationality + V/O types
# - the page numbers themselves (so that they get parsed) # - the page numbers themselves (so that they get parsed)
_VO_NOTE_SECTIONS = [ _VO_NOTE_SECTIONS = [
[ "german", "vehicles", "330,332,334-343", True ], [ "german", "vehicles", "335,337,339-348", True ],
[ "german", "ordnance", "344-348", True ], [ "german", "ordnance", "349-353", True ],
[ "russian", "vehicles", "348,350-355", True ], [ "russian", "vehicles", "353,355-360", True ],
[ "russian", "ordnance", "356-358", True ], [ "russian", "ordnance", "361-363", True ],
[ "russian", "vehicles", "362,364-368", False ], [ "russian", "vehicles", "367,369-373", False ],
[ "russian", "ordnance", "369", False ], [ "russian", "ordnance", "374", False ],
[ "american", "vehicles", "371,373-383", True ], [ "american", "vehicles", "376,378-388", True ],
[ "american", "ordnance", "385-389", True ], [ "american", "ordnance", "390-394", True ],
[ "british", "vehicles", "395,398-417", True ], [ "british", "vehicles", "400,403-422", True ],
[ "british", "ordnance", "419-423", True ], [ "british", "ordnance", "424-428", True ],
[ "italian", "vehicles", "429,431-435", True ], [ "italian", "vehicles", "434,436-440", True ],
[ "italian", "ordnance", "436-439", True ], [ "italian", "ordnance", "441-444", True ],
[ "japanese", "vehicles", "443-448", True ], [ "japanese", "vehicles", "449-454", True ],
[ "japanese", "ordnance", "448-452", True ], [ "japanese", "ordnance", "454-458", True ],
[ "chinese", "vehicles", "456-459", True ], [ "chinese", "vehicles", "462-465", True ],
[ "chinese", "ordnance", "459-463", True ], [ "chinese", "ordnance", "465-469", True ],
[ "landing-craft", "vehicles", "467-468", True ], [ "landing-craft", "vehicles", "473-474", True ],
[ "french", "vehicles", "470,472-480", True ], [ "french", "vehicles", "476,478-486", True ],
[ "french", "ordnance", "482-487", True ], [ "french", "ordnance", "488-493", True ],
[ "allied-minor", "vehicles", "492-493,495-500", True ], [ "allied-minor", "vehicles", "498-499,501-506", True ],
[ "allied-minor", "ordnance", "501-504", True ], [ "allied-minor", "ordnance", "507-510", True ],
[ "axis-minor", "vehicles", "506,508-515", True ], [ "axis-minor", "vehicles", "512,514-521", True ],
[ "axis-minor", "ordnance", "516,518-527", True ], [ "axis-minor", "ordnance", "522,524-533", True ],
[ "finnish", "vehicles", "536,538-541", True ], [ "finnish", "vehicles", "542,544-547", True ],
[ "finnish", "ordnance", "543,545-549", True ], [ "finnish", "ordnance", "549,551-555", True ],
[ "un-forces", "vehicles", "554,556-565", True ], [ "un-forces", "vehicles", "560,562-571", True ],
[ "un-forces", "ordnance", "567-570", True ], [ "un-forces", "ordnance", "573-576", True ],
[ "communist-forces", "vehicles", "580", True ], [ "communist-forces", "vehicles", "586", True ],
[ "communist-forces", "ordnance", "581-585", True ], [ "communist-forces", "ordnance", "587-591", True ],
] ]
# --------------------------------------------------------------------- # ---------------------------------------------------------------------
@ -103,7 +114,7 @@ class ExtractContent( ExtractBase ):
self._footnote_fixups = load_fixup( "footnote-fixups.json" ) self._footnote_fixups = load_fixup( "footnote-fixups.json" )
self._vo_note_fixups = load_fixup( "vo-note-fixups.json" ) self._vo_note_fixups = load_fixup( "vo-note-fixups.json" )
def extract_content( self, pdf ): def extract_content( self, pdf ): #pylint: disable=too-many-branches
"""Extract content from the MMP eASLRB.""" """Extract content from the MMP eASLRB."""
# figure out which pages to process # figure out which pages to process
@ -169,7 +180,10 @@ class ExtractContent( ExtractBase ):
def elem_filter( elem ): def elem_filter( elem ):
return isinstance( elem, LTChar ) return isinstance( elem, LTChar )
sort_elems = self._curr_pageid not in disable_sort_items and str(page_no) not in disable_sort_items sort_elems = self._curr_pageid not in disable_sort_items and str(page_no) not in disable_sort_items
for _, elem in PageElemIterator( lt_page, elem_filter=elem_filter, sort_elems=sort_elems ): centre_adjust = 35 if self._curr_footnote is not None and self._curr_chapter != "W" else 0
for _, elem in PageElemIterator( lt_page, centre_adjust=centre_adjust,
elem_filter=elem_filter, sort_elems=sort_elems
):
# skip problematic elements # skip problematic elements
if elem.fontname == "OYULKV+MyriadPro-Regular": if elem.fontname == "OYULKV+MyriadPro-Regular":
@ -238,6 +252,17 @@ class ExtractContent( ExtractBase ):
# loop back to process the next element # loop back to process the next element
self._prev_elem = elem self._prev_elem = elem
# check for extra targets that need to be added in
extra_targets = self._target_fixups.get( self._curr_pageid, {} ).pop( "extras", [] )
if extra_targets:
if not self._target_fixups[ self._curr_pageid ]:
del self._target_fixups[ self._curr_pageid ]
for extra_target in extra_targets:
self.targets[ extra_target["ruleid"] ] = {
"caption": extra_target.get("caption",""),
"page_no": page_no, "pos": extra_target["pos"]
}
# add the last caption/footnote (if they haven't already been done) # add the last caption/footnote (if they haven't already been done)
self._save_footnote() self._save_footnote()
if curr_caption: if curr_caption:
@ -277,7 +302,7 @@ class ExtractContent( ExtractBase ):
fixup = self._target_fixups.get( self._curr_pageid, {} ).get( caption_text ) fixup = self._target_fixups.get( self._curr_pageid, {} ).get( caption_text )
if fixup: if fixup:
# yup - make it so # yup - make it so
fixup[ "instances" ] = fixup.get("instances",1) - 1 fixup[ "instances" ] = fixup.get( "instances", 1 ) - 1
if fixup["instances"] <= 0: if fixup["instances"] <= 0:
self._target_fixups[ self._curr_pageid ].pop( caption_text ) self._target_fixups[ self._curr_pageid ].pop( caption_text )
if not self._target_fixups[ self._curr_pageid ]: if not self._target_fixups[ self._curr_pageid ]:
@ -325,7 +350,14 @@ class ExtractContent( ExtractBase ):
"""Process an element while we're parsing footnotes.""" """Process an element while we're parsing footnotes."""
# check if we've found the start of a new footnote # check if we've found the start of a new footnote
if self._is_bold( elem ): if self._is_bold( elem ):
if elem.get_text().isdigit() and self._is_start_of_line( elem, lt_page ): # FUDGE! The new Chapter F has things like "13. 7.1 SAND", which fooled the code into thinking
# that the "7" was the start of a new footnote (because it's a digit, and near the start
# of the line :-/), so we check for that case here.
def check():
if self._curr_chapter != "F" or not self._curr_footnote:
return False
return any( self._curr_footnote[0] == "{}. ".format(i) for i in range(10,15+1) )
if elem.get_text().isdigit() and self._is_start_of_line( elem, lt_page ) and not check():
# yup - save the current footnote, start collecting the new one # yup - save the current footnote, start collecting the new one
self._save_footnote() self._save_footnote()
elem_pos = ( elem.x0, elem.y1 ) elem_pos = ( elem.x0, elem.y1 )
@ -460,7 +492,7 @@ class ExtractContent( ExtractBase ):
# check for the credits at the end of the Chapter F footnotes # check for the credits at the end of the Chapter F footnotes
if self._curr_chapter == "F": if self._curr_chapter == "F":
pos = content.find( "WEST OF ALAMEIN CREDITS" ) pos = content.find( "HOLLOW LEGIONS CREDITS" )
if pos > 0: if pos > 0:
content = content[:pos] content = content[:pos]
# check for the start of the vehicle notes at the end of the Chapter H footnotes # check for the start of the vehicle notes at the end of the Chapter H footnotes
@ -477,6 +509,21 @@ class ExtractContent( ExtractBase ):
"raw_content": orig_content "raw_content": orig_content
} ) } )
self._curr_footnote = None self._curr_footnote = None
split = self._footnote_fixups.get( self._curr_chapter, {} ).pop( "split:"+footnote_id, None )
if split:
content = self._footnotes[self._curr_chapter][-1]["content"]
pos = content.find( split["split_text"] )
if pos < 0:
self.log_msg( "warning", "Can't find footnote split: {}", split["split_text"] )
else:
new_content = content[ pos + len( split["split_text"] ) : ]
self._footnotes[self._curr_chapter][-1]["content"] = content[:pos].strip()
self._footnotes[ self._curr_chapter ].append( {
"footnote_id": split["new_footnote_id"],
"captions": split["new_captions"],
"content": new_content.strip(),
"raw_content": None
} )
def _save_vo_note( self, caption, page_no, page_pos ): def _save_vo_note( self, caption, page_no, page_pos ):
"""Save an extracted vehicle/ordnance note.""" """Save an extracted vehicle/ordnance note."""
@ -494,7 +541,9 @@ class ExtractContent( ExtractBase ):
if not self._vo_note_fixups["skips"]: if not self._vo_note_fixups["skips"]:
del self._vo_note_fixups["skips"] del self._vo_note_fixups["skips"]
return return
if caption.isdigit() and page_no not in (354, 417): if caption.isdigit():
return
if not any( ch.isalpha() for ch in caption ):
return return
def apply_fixups( vo_note_id, caption ): def apply_fixups( vo_note_id, caption ):
@ -510,6 +559,9 @@ class ExtractContent( ExtractBase ):
vo_note_id = fixup["new_vo_note_id"] vo_note_id = fixup["new_vo_note_id"]
if "new_caption" in fixup: if "new_caption" in fixup:
caption = fixup["new_caption"] caption = fixup["new_caption"]
if "new_page_pos" in fixup:
nonlocal page_pos
page_pos = fixup["new_page_pos"]
return vo_note_id, caption return vo_note_id, caption
def cleanup_fixups( nat, vo_type ): def cleanup_fixups( nat, vo_type ):
@ -567,7 +619,11 @@ class ExtractContent( ExtractBase ):
elif base_note_id == prev_base_note_id and "." in vo_note_id: elif base_note_id == prev_base_note_id and "." in vo_note_id:
pass # nb: this is to allow things like "9.1" following "9" pass # nb: this is to allow things like "9.1" following "9"
else: else:
return # nb: we got some junk that can be ignored # NOTE: We used to return here, which ignored a lot of junk, but it has the unfortunate
# side-effect of, if we missed an entry, then all entries after that would also be missed.
# With v2.01 of the eASLRB, there were changes to the layout that weren't really fixable
# using the fixup data files, so we bit the bullet and manually ignore the junk :-/
pass
# save the V/O note # save the V/O note
self._vo_notes[ nat ][ vo_type ].append( { self._vo_notes[ nat ][ vo_type ].append( {

@ -25,7 +25,11 @@
"replace": { "replace": {
"B32": [ "RAILROADS10", "Railroads" ], "B32": [ "RAILROADS10", "Railroads" ],
"B34": [ "TOWERS18", "Towers" ], "B34": [ "TOWERS18", "Towers" ],
"B36": [ "PREPARED FIRE ZONE2", "Prepared Fire Zone" ] "B36": [ "PREPARED FIRE ZONE2", "Prepared Fire Zone" ],
"F1": [ "OPEN GROUND", "Open Ground" ],
"F2": [ "SCRUB", "Scrub" ],
"F4": [ "DEIRS", "Deirs" ],
"F5": [ "WADIS", "Wadis" ]
} }
} }

@ -2,20 +2,14 @@
"A": { "A": {
"10A": [ "10A": [ [ "One of the several criticisms", "<p> One of the several criticisms" ] ],
[ "OneHalfFP", "One-Half FP" ], "14": [ [ "bipodmounted", "bipod-mounted" ] ],
[ "firstappearedintheASLAnnual'89.(In1998,bothwerereprintedin Classic ASL.)", "first appeared in the ASL Annual '89. (In 1998, both were reprinted in Classic ASL.)" ], "19": [ [ "wellsited", "well-sited" ] ],
[ "One of the several criticisms", "<p> One of the several criticisms" ] "split:31A": {
], "split_text": "31B. 25.212 RUSSIAN EARLY WAR DOCTRINE:",
"12": [ [ "TEMto", "TEM to" ] ], "new_footnote_id": "31B",
"14": [ "new_captions": [ [ "A25.212", "RUSSIAN EARLY WAR DOCTRINE" ] ]
[ "bipodmounted", "bipod-mounted" ], },
[ "volume o f fire", "volume of fire" ]
],
"17": [ [ "adistinct", "a distinct" ] ],
"19" : [ [ "wellsited", "well-sited" ] ],
"32": [ [ "HWunits", "HW units" ] ],
"33": [ [ "multiLocation", "multi-Location" ] ],
"35": [ [ "The original printing", "<p> The original printing" ] ], "35": [ [ "The original printing", "<p> The original printing" ] ],
"37": [ "37": [
[ "- Winter War (vs Soviet Union) 30 November 1939 - 13 March 1940- Continuation War (vs Soviet Union) 25 June 1941 - 4 September 1944- Lapland War (vs Germany) 15 September 1944 - 27 April 1945", " <ul> <li> <b>Winter War</b> (vs Soviet Union) 30 November 1939 - 13 March 1940 <li> <b>Continuation War</b> (vs Soviet Union) 25 June 1941 - 4 September 1944 <li> <b>Lapland War</b> (vs Germany) 15 Se ptember 1944 - 27 April 1945 </ul>" ] [ "- Winter War (vs Soviet Union) 30 November 1939 - 13 March 1940- Continuation War (vs Soviet Union) 25 June 1941 - 4 September 1944- Lapland War (vs Germany) 15 September 1944 - 27 April 1945", " <ul> <li> <b>Winter War</b> (vs Soviet Union) 30 November 1939 - 13 March 1940 <li> <b>Continuation War</b> (vs Soviet Union) 25 June 1941 - 4 September 1944 <li> <b>Lapland War</b> (vs Germany) 15 Se ptember 1944 - 27 April 1945 </ul>" ]
@ -26,16 +20,12 @@
[ "Slovakia: Urged on", "<p> <b>Slovakia</b>: Urged on" ], [ "Slovakia: Urged on", "<p> <b>Slovakia</b>: Urged on" ],
[ "German-Croatian units in Russia:", " <p> <b>German-Croatian units in Russia</b>:" ], [ "German-Croatian units in Russia:", " <p> <b>German-Croatian units in Russia</b>:" ],
[ "Italian-Croatian units in Russia:", " <p> <b>Italian-Croatian units in Russia</b>:" ], [ "Italian-Croatian units in Russia:", " <p> <b>Italian-Croatian units in Russia</b>:" ],
[ "existing GermanCroatian units", "existing German-Croatian units" ],
[ "Croatian units in Yugoslavia:", " <p> <b>Croatian units in Yugoslavia</b>:" ], [ "Croatian units in Yugoslavia:", " <p> <b>Croatian units in Yugoslavia</b>:" ],
[ "CroatianArmyunitswereengagedprimarilyinanti-partisanactivities,fightingmostly", "Croatian Army units were engaged primarily in anti-partisan activities, fighting mostly" ], [ "Bulgaria: Bulgaria", "<p> <b>Bulgaria</b>: Bulgaria" ]
[ "Bulgaria: Bulgaria", "<p> <b>Bulgaria</b>: Bulgaria" ],
[ "WhiletheriflecompanydidnothaveaninherentHeavyWeapons(HW)platoon,it", "While the rifle company did not have an inherent Heavy Weapons (HW) platoon, it"]
], ],
"39": [ [ "generallyapply", "generally apply" ] ], "42": [
"41": [ [ "ViceAdmiral", "Vice-Admiral" ] ], [ "twoman", "two-man" ]
"43": [
[ "ALLIEDMINORS", "ALLIED MINORS" ],
[ "BARrather", "BAR rather" ]
] ]
}, },
@ -107,51 +97,14 @@
"F": { "F": {
"split:7": {
"split_text": "8. 5.1 WADIS:",
"new_footnote_id": "8",
"new_captions": [ [ "F5.1", "WADIS" ] ]
},
"12": [ [ "non- entrenched", "non-entrenched" ] ], "12": [ [ "non- entrenched", "non-entrenched" ] ],
"19": [ "19": [ [ "nearfreezing", "near-freezing" ] ]
[ "Inthewinternight,thenear-freezingtemperaturecauseddewtoform.", "In the winter night, the near-freezing temperature caused dew to form. " ],
[ "Thenextmorningathickmistoftenformedasthesun evaporateditagain.", "The next morning a thick mist often formed as the sun evaporated it again. " ],
[ "Thiscouldhappeneveninthesummertimeundertheproperenvironmentalconditions,", "This could happen even in the summertime under the proper environmental conditions, " ],
[ "butsincethiswasamuchlessfrequentoccurrenceithasbeen ignored.", "but since this was a much less frequent occurrence it has been ignored." ]
],
"21": [
[ "Playerswillprobablyfinditmoreconvenienttoinstead", "Players will probably find it more convenient to instead" ],
[ "addathird,different-coloreddietothisTH/IFTDR,", "add a third, different-colored die to this TH/IFT DR, " ],
[ "usingittodeterminetheDust DRM.", "using it to determine the Dust DRM." ],
[ "Thefamiliarterm\"subsequentdr\"wasusedintherulebecauseitobviates theneed", "The familiar term \"subsequent dr\" was used in the rule because it obviates the need" ],
[ "a\"new\"concept", "a \"new\" concept" ],
[ "thatof rolling athird diesimultaneously", "that of rolling a third die simultaneously" ]
],
"22": [
[ "theDustcounter\"follows\"thevehicleasit movesfromhex to hex", "the Dust counter \"follows\" the vehicle as it moves from hex to hex" ],
[ "itexpends", "it expends " ],
[ "two MPeach timeitdoesso", " two MP each time it does so" ]
],
"23": [
[ "Anotherwind-relatedaspectoftheNorthAfricanenvironmentisthedesertsandstorm,", "Another wind-related aspect of the North African environment is the desert sandstorm, " ],
[ "orkhamsininArabic.", "or khamsin in Arabic. " ],
[ "ChapterFincludesnospecial rulesforitbecause,", "Chapter F includes no special rules for it because, " ],
[ "withvisibilitycutbythestormtoaslittleasthreeyards,", "with visibility cut by the storm to as little as three yards, " ],
[ "allactivitiesgenerallywerereducedtoseekingcoverfromthesandblastingwindandchoking dust.", "all activities generally were reduced to seeking cover from the sandblasting wind and choking dust. " ],
[ "However,thegamedoesnotignorethepossibilityofakhamsin'soccurrence.", "However, the game does not ignore the possibility of a khamsin's occurrence. " ],
[ "The propercombinationofWeather,EC,WindandGustsinaDYOscenariocancreateits effects,", "The proper combination of Weather, EC, Wind and Gusts in a DYO scenario can create its effects, " ],
[ "andtheprobabilityofitsoccurrenceisgreatestinascenariosetinspringor summer", "and the probability of its occurrence is greatest in a scenario set in spring or summer" ],
[ "thetimewhen khamsinsoccurred mostfrequently.", "the time when khamsins occurred most frequently." ]
],
"24": [
[ "Thisoverlay isused in aHOLLOW LEGIONS scenario.", "This overlay is used in a HOLLOW LEGIONS scenario." ]
],
"25": [
[ "ThefamousNorthAfricanescarpmentsaresimilarto cliffs,", "The famous North African escarpments are similar to cliffs, " ],
[ "butwithlesssteep(andveryeroded)slopes.", "but with less steep (and very eroded) slopes. " ],
[ "Somearesixhundredfeethigh", "Some are six hundred feet high" ],
[ "thoughgenerallytheirheightsrangefromonehundredtotwohundredfeet.", "though generally their heights range from one hundred to two hundred feet. " ],
[ "Theirsignificanceinthedesertwarlaymainlyinthattheywerecommandingheights,", "Their significance in the desert war lay mainly in that they were commanding heights, " ] ,
[ "defensivepositionsforinfantry,", "defensive positions for infantry, " ],
[ "andgreatlyrestrictedvehicularmovementacrossthem", "and greatly restricted vehicular movement across them" ],
[ "Hencetheywereoftenthesceneofheavyfighting,", "Hence they were often the scene of heavy fighting, " ],
[ "especiallywherecrossedbya road", "especially where crossed by a road" ]
]
}, },
"G": { "G": {

@ -66,6 +66,13 @@
"new_content": "(Any fire attack requiring a LOS from the firer which does not use Indirect Fire): C.1, C9.1 [Intervening Units: A6.6] [LC: G12.61-.62, G12.671]" "new_content": "(Any fire attack requiring a LOS from the firer which does not use Indirect Fire): C.1, C9.1 [Intervening Units: A6.6] [LC: G12.61-.62, G12.671]"
}, },
"Dispersed Smoke": {
"replace": [
[ "SmokeGrenadesNA", "Smoke Grenades NA" ],
[ "VehicularSmoke", "Vehicular Smoke" ]
]
},
"Dogfight": { "Dogfight": {
"old_content": "(AerialCombat):E7.22", "old_content": "(AerialCombat):E7.22",
"new_content": "(Aerial Combat): E7.22" "new_content": "(Aerial Combat): E7.22"

@ -108,18 +108,10 @@
} }
}, },
"A54": {
"25.53 FREEFRENCH:": {
"new_ruleid": "A25.53",
"new_caption": "FREE FRENCH"
}
},
"A55": { "A55": {
"26.VICTORYCONDITIONS": { "extras": [
"new_ruleid": "A26", { "ruleid": "A25.71", "caption": "LEADERS", "pos": [172,714] }
"new_caption": "VICTORY CONDITIONS" ]
}
}, },
"B1": { "B1": {
@ -132,7 +124,10 @@
"T10": { "new_ruleid": null }, "T10": { "new_ruleid": null },
"W5": { "new_ruleid": null }, "W5": { "new_ruleid": null },
"V5": { "new_ruleid": null }, "V5": { "new_ruleid": null },
"X6": { "new_ruleid": null } "X6": { "new_ruleid": null },
"Y6": { "new_ruleid": null },
"Y7": { "new_ruleid": null },
"Y10": { "new_ruleid": null }
}, },
"B4": { "B4": {
@ -348,10 +343,86 @@
"3)": { "new_ruleid": null } "3)": { "new_ruleid": null }
}, },
"F18": { "F1": {
"D3": { "new_ruleid": null }, "8½ 1 3 3 5 1 7": { "new_ruleid": null },
"W1": { "new_ruleid": null }, "1 1": { "new_ruleid": null },
"H4": { "new_ruleid": null } "17": { "new_ruleid": null }
},
"F2": {
"1. OPEN GROUND 1.1": {
"new_ruleid": "F1",
"new_caption": "OPEN GROUND"
},
"2. SCRUB 2.1": {
"new_ruleid": "F2",
"new_caption": "SCRUB"
},
"extras": [
{ "ruleid": "F1.1", "pos": [18,330] },
{ "ruleid": "F2.1", "pos": [18,173] },
{ "ruleid": "F3", "caption": "HAMMADA", "pos": [294,592] },
{ "ruleid": "F3.1", "pos": [294,582] }
]
},
"F3": {
"4. DEIRS 7 4.1": {
"new_ruleid": "F4",
"new_caption": "DEIRS"
},
"5. WADIS 8 5.1": {
"new_ruleid": "F5",
"new_caption": "WADIS"
},
"extras": [
{ "ruleid": "F4.1", "pos": [66,109] },
{ "ruleid": "F5.1", "pos": [342,166] }
]
},
"F6": {
"3 TEM:": {
"new_ruleid": "F5.423",
"new_caption": "TEM"
}
},
"F7": {
"extras": [
{ "ruleid": "F6", "caption": "HILLOCKS", "pos": [66,276] }
]
},
"F8": {
"extras": [
{ "ruleid": "F7", "caption": "SAND", "pos": [294,531] },
{ "ruleid": "F7.1", "pos": [294,520] }
]
},
"F12": {
"11.4": {
"new_ruleid": "F11.4",
"new_caption": "ENVIRONMENTAL CONDITIONS"
},
"18": { "new_ruleid": null },
"extras": [
{ "ruleid": "F11.3", "caption": "TIME OF DAY", "pos": [294,529] }
]
},
"F14": {
"20 11.7 DUST:": {
"new_ruleid": "F11.7",
"new_caption": "DUST"
},
"21": { "new_ruleid": null },
"22": { "new_ruleid": null }
},
"F15": {
"23": { "new_ruleid": null }
}, },
"G30": { "G30": {

@ -1,23 +1,27 @@
{ {
"skips": { "skips": {
"382": [ "1, 3" ], "342": [ "5.1 GSW 39H(f) PaK:" ],
"429": [ "^1,660,", "^1and Fiat 3000", "^9/43 armistice", "^4/41 (.9)" ], "345": [ "4 FP", "4 FP", "6 FP", "4 FP", "4 FP", "4 FP", "6 FP", "4 FP" ],
"431": [ "^1, for East Africa", "^9/42 (1.4)," ], "355": [ "26S M37/39:" ],
"432": [ "^1 (l.2),", "^1. Sources vary" ], "422": [ "30-cwt Lorry:", "3-Ton Lorry:" ],
"434": [ "1-", "^1.5 for 11/41-6/42," ], "463": [ "243M2" ],
"438": [ "^1/41-5/43" ], "466": [ "^50mm RM obr. 38," ],
"439": [ "1 (1", "^1/43 ( 1.2),", "^1/43 (1.3),", "^1/42-5/43." ], "468": [ "20/65, & 2cm FlaK 30:" ],
"492": [ "1B11CE/FPNA", "1B11CE/FPNA" ], "485": [ "4, M4A1, & M4A2 Medium Tanks:" ],
"493": [ "1T", "1B" ], "498": [ "11:Stall", "11:Stall", "1B11CE/FPNA", "1B11CE/FPNA", "2x" ],
"496": [ "1B" ], "499": [ "1T", "1B", "2B11B11" ],
"501": [ "1h-d" ], "501": [ "4PP", "5PPcs 5", "5PP" ],
"502": [ "1s5", "1s5" ], "502": [ "1B" ],
"503": [ "1AP5", "1s6" ], "504": [ "2/2CS 6" ],
"504": [ "^1.3)" ], "505": [ "9PPcs 2", "9PP*" ],
"514": [ "1.4 for 45" ], "506": [ "29PP", "21PP", "9PP", "9PP" ],
"556": [ "1#" ], "507": [ "4M", "1h-d", "11M" ],
"560": [ "1, 3" ] "508": [ "8M", "12M", "8M", "1s5", "11M", "12M" ],
"509": [ "3/42 RR1", "10M", "8M", "9M(9/39-s6", "5/40 RF 1.5", "4/41 RF 1.4", "8M", "6M", "^10/39 RF" ],
"510": [ "^1.3)", "^5/40 RF", "8M" ],
"519": [ "8/43; a", "^38(t)E is 1.3" ],
"520": [ "1.4 for 45", "44, and 1.4 for 45" ]
}, },
"german": { "german": {
@ -63,16 +67,22 @@
"new_caption": "2cm & 3.7cm FlaK LKW" "new_caption": "2cm & 3.7cm FlaK LKW"
}, },
"96": { "96": {
"old_caption": "Opel 6700 &Buessing-NAG", "old_caption": "Opel 6700 &",
"new_caption": "Opel 6700 & Buessing-NAG 4500" "new_caption": "Opel 6700 & Buessing-NAG 4500"
}, },
"add": [ "add": [
{ "_comment_": "This gets parsed as '4' and '5.1 GSW 39H(f) PaK' :-/", { "_comment_": "This gets parsed as '4' and '5.1 GSW 39H(f) PaK' :-/",
"vo_note_id": "45.1", "caption": "GSW 39H(f) PaK", "page_no": 337, "page_pos": [380,561] "vo_note_id": "45.1", "caption": "GSW 39H(f) PaK", "page_no": 342, "page_pos": [380,561]
}, },
{ "vo_note_id": "37.1", "caption": "Sturmtiger", "page_no": 532, "page_pos": [118,640] }, { "vo_note_id": "37.1", "caption": "Sturmtiger", "page_no": 538, "page_pos": [118,640] },
{ "vo_note_id": "88.1", "caption": "SdKfz 10/5", "page_no": 532, "page_pos": [399,713] } { "vo_note_id": "88.1", "caption": "SdKfz 10/5", "page_no": 538, "page_pos": [399,713] }
] ]
},
"ordnance": {
"29": {
"old_caption": "3.7cm FlaK 43: O",
"new_caption": "3.7cm FlaK 43"
}
} }
}, },
@ -99,7 +109,9 @@
"new_caption": "ISU-122 & ISU-152" "new_caption": "ISU-122 & ISU-152"
}, },
"add": [ "add": [
{ "vo_note_id": "12.1", "caption": "T-28E M40(L)", "page_no": 364, "page_pos": [394,289] } { "vo_note_id": "47", "caption": "", "page_no": 359, "page_pos": [461,580] },
{ "vo_note_id": "12.1", "caption": "T-28E M40(L)", "page_no": 369, "page_pos": [394,289] },
{ "vo_note_id": "48", "caption": "Stuart III(a)", "page_no": 371, "page_pos": [394,515] }
] ]
} }
}, },
@ -111,7 +123,7 @@
"new_caption": "M4A3E2 & M4A3E2 (L) Medium Tanks" "new_caption": "M4A3E2 & M4A3E2 (L) Medium Tanks"
}, },
"17": { "17": {
"old_caption": "M4(105) & M4A3(105) MediumTanks", "old_caption": "M4(105) & M4A3(105) Medium",
"new_caption": "M4(105) & M4A3(105) Medium Tanks" "new_caption": "M4(105) & M4A3(105) Medium Tanks"
} }
} }
@ -120,7 +132,7 @@
"british": { "british": {
"vehicles": { "vehicles": {
"2": { "2": {
"old_caption": "(A17) Tetrarch & Tetrarch CS[Light Tanks Mk VII & Mk VII CS]", "old_caption": "(A17) Tetrarch & Tetrarch CS",
"new_caption": "(A17) Tetrarch & Tetrarch CS [Light Tanks Mk VII & Mk VII CS]" "new_caption": "(A17) Tetrarch & Tetrarch CS [Light Tanks Mk VII & Mk VII CS]"
}, },
"6": { "6": {
@ -132,211 +144,34 @@
"new_caption": "(A12) Matilda II & II CS [Infantry Tank Mk II]" "new_caption": "(A12) Matilda II & II CS [Infantry Tank Mk II]"
}, },
"36": { "36": {
"old_caption": "Valentine & Churchill Bridgelay-ers", "old_caption": "Valentine & Churchill Bridgelay-",
"new_caption": "Valentine & Churchill Bridgelayers" "new_caption": "Valentine & Churchill Bridgelayers"
}, },
"45": { "45": {
"old_caption": "Humber III & Otter Light Re-connaissance Cars", "old_caption": "Humber III & Otter Light Re-connaissance Cars",
"new_caption": "Humber III & Otter Light Reconnaissance Cars" "new_caption": "Humber III & Otter Light Reconnaissance Cars"
}, },
"82": { "54": {
"old_caption": "", "old_caption": "Staghound I(a) & II(a) Armoured",
"new_caption": "30-cwt Lorry" "new_caption": "Staghound I(a) & II(a) Armoured Cars"
}, },
"83": { "add": [
"old_caption": "", { "vo_note_id": "82", "caption": "30-cwt Lorry", "page_no": 422, "page_pos": [116,475] },
"new_caption": "3-Ton Lorry" { "vo_note_id": "83", "caption": "3-Ton Lorry", "page_no": 422, "page_pos": [116,287] }
]
},
"ordnance": {
"16": {
"old_caption": "OBL 4.5-in. Gun & 5.5-in. Gun-",
"new_caption": "OBL 4.5-in. Gun & 5.5-in. Gun-Howitzer"
} }
} }
}, },
"italian": { "italian": {
"vehicles": { "vehicles": {
"1": {
"old_caption": "LS/21 & LS/3",
"new_caption": "L5/21 & L5/30"
},
"2": {
"old_caption": "^L3/35: Derived from",
"new_caption": "L3/35"
},
"3": {
"old_caption": "^L3 aa: Some L3",
"new_caption": "L3 aa"
},
"4": {
"old_caption": "^L3 cc: During the early months",
"new_caption": "L3 cc"
},
"5": {
"old_caption": "^L3 Lf: Development of",
"new_caption": "L3 Lf"
},
"6": {
"old_caption": "^L6/40: Designed to replace",
"new_caption": "L6/40"
},
"7": {
"old_caption": "^Mll/39: This tank carried",
"new_caption": "M11/39"
},
"8": {
"old_caption": "^Ml3/40: Replacing the",
"new_caption": "M13/40"
},
"9": {
"old_caption": "^M14/41: This tank,",
"new_caption": "M14/41"
},
"10": {
"old_caption": "^M15/42: This, the last version",
"new_caption": "M15/42"
},
"11": {
"old_caption": "^MR/35(f): The Germans provided",
"new_caption": "MR/35(f)"
},
"12": {
"old_caption": "Semovente M40 & M41 da",
"new_caption": "Semovente M40 & M41 da 75/18"
},
"13": {
"old_caption": "^Semovente M42 da 75/1&75/32: The last model",
"new_caption": "Semovente M42 da 75/18 & 75/32"
},
"14": {
"old_caption": "^Semovente M43 da 105/25: Nicknathe",
"new_caption": "Semovente M43 da 105/25"
},
"15": {
"old_caption": "Semovente L40 da 47/32: The SMV",
"new_caption": "Semovente L40 da 47/32"
},
"16": {
"old_caption": "^Semovente M41M da 90/53: This AFV",
"new_caption": "Semovente M41M da 90/53"
},
"18": {
"old_caption": "^Lince: The Lince (Lynx)",
"new_caption": "Lince"
},
"19": {
"old_caption": "^Lancia lZM: In late 1912",
"new_caption": "Lancia 1ZM"
},
"20": {
"old_caption": "^Fiat 611A & 611BThese armoredcars",
"new_caption": "Fiat 611A & 611B"
},
"21": {
"old_caption": "^AB 40 & AB41These two auto",
"new_caption": "AB 40 & AB 41"
},
"22": {
"old_caption": "^Autoprotetto S37: This APC",
"new_caption": "Autoprotetto S37"
},
"23": {
"old_caption": "Autocannoni da",
"new_caption": "Autocannoni da 20/65(b) & 65/17(b)"
},
"24": {
"old_caption": "Autocannoni da",
"new_caption": "Autocannoni da 75/27 CK & 90/53"
},
"25": {
"old_caption": "^TL 37, TM 40 &TP 32",
"new_caption": "TL 37, TM 40 & TP 32"
},
"26": {
"old_caption": "^Autocarretta: As the portee",
"new_caption": "Autocarretta"
},
"27": {
"old_caption": "^Fiat 508 MC: Derived from",
"new_caption": "Fiat 508 MC"
},
"28": {
"old_caption": "^Autocarri L, M & P: The ItalianArmy",
"new_caption": "Autocarri L, M & P"
}
},
"ordnance": {
"1": {
"old_caption": "^Mortaio da 45 \"Brixia\": This weapon,",
"new_caption": "Mortaio da 45 \"Brixia\""
},
"2": {
"old_caption": "^Mortaio da 81/14: First usedi",
"new_caption": "Mortaio da 81/14"
},
"3": {
"old_caption": "^Fucile-cc S: Like several other",
"new_caption": "Fucile-cc S"
},
"4": {
"old_caption": "^Cannone-cc da 37/45: This was",
"new_caption": "Cannone-cc da 37/45"
},
"5": {
"old_caption": "^Cannone da 47/32: This was",
"new_caption": "Cannone da 47/32"
},
"6": {
"old_caption": "^Cannone da 65/17: This was",
"new_caption": "Cannone da 65/17"
},
"7": {
"old_caption": "^Cannone da 70/15: This",
"new_caption": "Cannone da 70/15"
},
"8": {
"old_caption": "^Obice da 75/13: The Skoda",
"new_caption": "Obice da 75/13"
},
"9": {
"old_caption": "^Cannone da 75/27: This was",
"new_caption": "Cannone da 75/27"
},
"10": {
"old_caption": "^Obice da 75/18: This game piece",
"new_caption": "Obice da 75/18"
},
"11": {
"old_caption": "^Cannone da 75/32: The 75/32",
"new_caption": "Cannone da 75/32"
},
"12": {
"old_caption": "^Obice da 100/17: Another old",
"new_caption": "Obice da 100/17"
},
"13": {
"old_caption": "^Cannone da 105/28: This was",
"new_caption": "Cannone da 105/28"
},
"14": {
"old_caption": "^Obice da 149/13: This piece",
"new_caption": "Obice da 149/13"
},
"15": {
"old_caption": "^Cannone da 149/35: Another",
"new_caption": "Cannone da 149/35"
},
"16": {
"old_caption": "^Cannone da 149/40: To replace",
"new_caption": "Cannone da 149/40"
},
"17": {
"old_caption": "^Cannone-mitragliera da 20/65: Thiswas",
"new_caption": "Cannone-mitragliera da 20/65"
},
"18": {
"old_caption": "^Cannone-aa da 75/39: This was",
"new_caption": "Cannone-aa da 75/39"
},
"add": [ "add": [
{ "vo_note_id": "19", "caption": "Cannone-aa da 75/46", "page_no": 439, "page_pos": [283,42] }, { "vo_note_id": "12", "caption": "Semovente M40 & M41 da 75/18", "page_no": 437, "page_pos": [442,715] }
{ "vo_note_id": "20", "caption": "Cannone-aa da 90/53", "page_no": 439, "page_pos": [384,541] }
] ]
} }
}, },
@ -383,17 +218,16 @@
"new_caption": "Year-3 Type 14cm Naval Seacoast Gun" "new_caption": "Year-3 Type 14cm Naval Seacoast Gun"
}, },
"20": { "20": {
"old_caption": "Type 93 Twin-Mount High-Angle Ma-chine Gun", "old_caption": "Type 93 Twin-Mount High-Angle Ma-",
"new_caption": "Type 93 Twin-Mount High-Angle Machine Gun" "new_caption": "Type 93 Twin-Mount High-Angle Machine Gun"
}, },
"22": {
"old_caption": "Type 96 Single-, Twin-, & Triple-Mount Naval High-Angle Machine Can-",
"new_caption": "Type 96 Single-, Twin-, & Triple-Mount Naval High-Angle Machine Cannons"
},
"24": { "24": {
"old_caption": "Year-10 Type 12cm Naval High-AngleGun", "old_caption": "Year-10 Type 12cm Naval High-AngleGun",
"new_caption": "Year-10 Type 12cm Naval High-Angle Gun" "new_caption": "Year-10 Type 12cm Naval High-Angle Gun"
} },
"add": [
{ "vo_note_id": "22", "caption": "Type 96 Single-, Twin-, & Triple-Mount Naval High-Angle Machine Cannons", "page_no": 458, "page_pos": [395,713] }
]
} }
}, },
@ -433,31 +267,51 @@
"french": { "french": {
"vehicles": { "vehicles": {
"20": { "20": {
"old_caption": "Autocanon de 75 mle 97 & Autocanonde 75 Conus(b)", "old_caption": "CA, & Autocanon de 25 CA",
"new_caption": "Autocanon de 75 mle 97 & Autocanon de 75 Conus(b)" "new_caption": "Autocanon de 75 mle 97 & Autocanon de 75 Conus(b)",
"new_page_pos": [395,715]
}, },
"21": { "21": {
"old_caption": "Camion de Mitrailleuse Contre-Avions, Camion de 13.2 CAJ, Camion de", "old_caption": "Camion de Mitrailleuse Contre-Avions, Camion de 13.2 CAJ, Camion de",
"new_caption": "Camion de Mitrailleuse Contre-Avions, Camion de 13.2 CAJ, Camion de 20 CA, & Autocanon de 25 CA" "new_caption": "Camion de Mitrailleuse Contre-Avions, Camion de 13.2 CAJ, Camion de 20 CA, & Autocanon de 25 CA"
}, },
"36": { "36": {
"old_caption": "Peugeot 202, Citroën 23, & RenaultAGR2", "old_caption": "Peugeot 202, Citroën 23, & Renault#NaAGR2",
"new_caption": "Peugeot 202, Citroën 23, & Renault AGR2" "new_caption": "Peugeot 202, Citroën 23, & Renault AGR2"
}, },
"38": {
"old_caption": "Cr",
"new_caption": "Crusader II & III Tanks"
},
"39": {
"old_caption": "M",
"new_caption": "M4, M4A1, & M4A2 Medium Tanks"
},
"40": { "40": {
"old_caption": "M4A3(75)W, M4A3(76)W, & M4A3(105) Medium Tanks, & M4Tankdozer", "old_caption": "M4A3(75)W, M4A3(76)W, & M4A3(105) Medium Tanks, & M4Tankdozer",
"new_caption": "M4A3(75)W, M4A3(76)W, & M4A3(105) Medium Tanks, & M4 Tankdozer" "new_caption": "M4A3(75)W, M4A3(76)W, & M4A3(105) Medium Tanks, & M4 Tankdozer"
} },
"add": [
{ "vo_note_id": "11", "caption": "D2 & D2(L)", "page_no": 479, "page_pos": [395,715] },
{ "vo_note_id": "15", "caption": "AM Dodge(a)", "page_no": 480, "page_pos": [444,715] }
]
}, },
"ordnance": { "ordnance": {
"6": { "6": {
"old_caption": "Canon Antichar de 47SA mle 37 APX", "old_caption": "Canon Antichar de 47",
"new_caption": "Canon Antichar de 47 SA mle 37 APX" "new_caption": "Canon Antichar de 47 SA mle 37 APX"
}, },
"18": { "18": {
"old_caption": "Mitrailleuse de 13.2 CAJmle 30", "old_caption": "Mitrailleuse de 13.2 CAJmle 30",
"new_caption": "Mitrailleuse de 13.2 CAJ mle 30" "new_caption": "Mitrailleuse de 13.2 CAJ mle 30"
} },
"27": {
"old_caption": "M2A1 & M3 105mm Howitzers: C",
"new_caption": "M2A1 & M3 105mm Howitzers"
},
"add": [
{ "vo_note_id": "26", "caption": "OQF 25-Pounder Gun-Howitzer", "page_no": 493, "page_pos": [18,715] }
]
} }
}, },
@ -494,7 +348,7 @@
"new_caption": "M3A3(a) FlaK 38" "new_caption": "M3A3(a) FlaK 38"
}, },
"29": { "29": {
"old_caption": "Marmon-Herrington III(b) Armored", "old_caption": "Marmon-Herrington III(b) Armored*2 TK DR",
"new_caption": "Marmon-Herrington III(b) Armored Cars" "new_caption": "Marmon-Herrington III(b) Armored Cars"
}, },
"31": { "31": {
@ -502,7 +356,7 @@
"new_caption": "L5/30(i) & L3/35(i) & L6/40(i) & M13/40(i)" "new_caption": "L5/30(i) & L3/35(i) & L6/40(i) & M13/40(i)"
}, },
"37": { "37": {
"old_caption": "Light Truck & Medium Truck &", "old_caption": "Light Truck & Medium Truck &Heavy Truck",
"new_caption": "Light Truck & Medium Truck & Heavy Truck" "new_caption": "Light Truck & Medium Truck & Heavy Truck"
} }
}, },
@ -513,7 +367,7 @@
"new_caption": "75M 19S" "new_caption": "75M 19S"
}, },
"add": [ "add": [
{ "vo_note_id": "20", "caption": "3.7cm Infantry Gun", "page_no": 502, "page_pos": [393,616] } { "vo_note_id": "20", "caption": "3.7cm Infantry Gun", "page_no": 508, "page_pos": [393,616] }
] ]
} }
}, },
@ -555,10 +409,17 @@
"new_vo_note_id": "16", "new_vo_note_id": "16",
"new_caption": "40M Nimrod" "new_caption": "40M Nimrod"
}, },
"39": {
"old_caption": "PzKpfw IVD(g), PzKpfw IVF1(g),",
"new_caption": "PzKpfw IVD(g), PzKpfw IVF1(g), & PzKpfw IVH(g)"
},
"50": { "50": {
"old_caption": "Light Truck, Medium Truck, &Heavy Truck", "old_caption": "Light Truck, Medium Truck, &Heavy Truck",
"new_caption": "Light Truck, Medium Truck, & Heavy Truck" "new_caption": "Light Truck, Medium Truck, & Heavy Truck"
} },
"add": [
{ "vo_note_id": "48", "caption": "RSO(g)", "page_no": 521, "page_pos": [394,713] }
]
}, },
"ordnance": { "ordnance": {
"20": { "20": {
@ -689,7 +550,10 @@
"old_caption": "ItK/31(r)", "old_caption": "ItK/31(r)",
"new_vo_note_id": "39", "new_vo_note_id": "39",
"new_caption": "76 ItK/31(r)" "new_caption": "76 ItK/31(r)"
} },
"add": [
{ "vo_note_id": "24", "caption": "105 H/37", "page_no": 553, "page_pos": [394,713] }
]
} }
}, },
@ -708,7 +572,7 @@
"new_caption": "M4A3E8(a) Medium Tank & M4A3E8 Dozer(a)" "new_caption": "M4A3E8(a) Medium Tank & M4A3E8 Dozer(a)"
}, },
"47": { "47": {
"old_caption": "Oxford Carrier, MMG & Oxford Car-rier, HMG", "old_caption": "Oxford Carrier, MMG & Oxford Car-",
"new_caption": "Oxford Carrier, MMG & Oxford Carrier, HMG" "new_caption": "Oxford Carrier, MMG & Oxford Carrier, HMG"
}, },
"57": { "57": {

@ -15,7 +15,7 @@ from asl_rulebook2.utils import parse_page_numbers, fixup_text, extract_parens_c
# --------------------------------------------------------------------- # ---------------------------------------------------------------------
_DEFAULT_ARGS = { _DEFAULT_ARGS = {
"pages": "10-41", "pages": "10-42",
"index_vp_left": 0, "index_vp_right": 565, "index_vp_top": 715, "index_vp_bottom": 20, # viewport "index_vp_left": 0, "index_vp_right": 565, "index_vp_top": 715, "index_vp_bottom": 20, # viewport
"first_title": "a", "last_title": "X#", # first/last index entries "first_title": "a", "last_title": "X#", # first/last index entries
} }

@ -111,7 +111,7 @@ class PageIterator:
class PageElemIterator: class PageElemIterator:
"""Iterate over each element in a page.""" """Iterate over each element in a page."""
def __init__( self, lt_page, elem_filter=None, sort_elems=False ): def __init__( self, lt_page, elem_filter=None, sort_elems=False, centre_adjust=0 ):
self.lt_page = lt_page self.lt_page = lt_page
# collect all the elements (so that they can be sorted) # collect all the elements (so that they can be sorted)
self._elems = [] self._elems = []
@ -127,7 +127,7 @@ class PageElemIterator:
walk( lt_page, 0 ) walk( lt_page, 0 )
if sort_elems: if sort_elems:
def sort_key( elem ): def sort_key( elem ):
col_no = 0 if elem[1].x0 < lt_page.width/2 else 1 col_no = 0 if elem[1].x0 < lt_page.width/2 + centre_adjust else 1
# NOTE: Some elements that should be aligned are actually misaligned by a miniscule amount (e.g. 10^-5), # NOTE: Some elements that should be aligned are actually misaligned by a miniscule amount (e.g. 10^-5),
# so to stop this from resulting in the wrong sort order, we truncate the decimal places. # so to stop this from resulting in the wrong sort order, we truncate the decimal places.
# NOTE: Characters are often rendered in different fonts, with bounding boxes that don't align neatly. # NOTE: Characters are often rendered in different fonts, with bounding boxes that don't align neatly.

@ -140,7 +140,7 @@ gPrepareApp.component( "upload-panel", {
Click on the button, and select your copy of MMP's eASLRB. Click on the button, and select your copy of MMP's eASLRB.
<div class="info"> You <u>must</u> use the <a href="https://www.wargamevault.com/product/344879/Electronic-Advanced-Squad-Leader-Rulebook" target="_blank">offical MMP eASLRB</a>. <br> <div class="info"> You <u>must</u> use the <a href="https://www.wargamevault.com/product/344879/Electronic-Advanced-Squad-Leader-Rulebook" target="_blank">offical MMP eASLRB</a>. <br>
A scan of a printed rulebook <u>will not work</u>! A scan of a printed rulebook <u>will not work</u>!
<p> You should use v1.07 of the eASLRB PDF (normal version, not the "inherited zoom" version). Other versions <i>may</i> work, but may have warnings and/or errors. </p> <p> You should use v2.01 of the eASLRB PDF (normal version, not the "inherited zoom" version). Other versions <i>may</i> work, but may have warnings and/or errors. </p>
</div> </div>
</div> </div>
</div> </div>

Loading…
Cancel
Save