Compare commits
155 Commits
Before Width: | Height: | Size: 1.8 MiB After Width: | Height: | Size: 3.8 MiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 109 KiB |
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.8 MiB |
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 902 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 61 KiB |
After Width: | Height: | Size: 3.4 KiB |
@ -0,0 +1,107 @@ |
|||||||
|
#!/usr/bin/env python3 |
||||||
|
""" Freeze the vasl-templates loader program. |
||||||
|
|
||||||
|
This script is called by the main freeze script. |
||||||
|
""" |
||||||
|
|
||||||
|
import sys |
||||||
|
import os |
||||||
|
import shutil |
||||||
|
import tempfile |
||||||
|
import getopt |
||||||
|
|
||||||
|
from PyInstaller.__main__ import run as run_pyinstaller |
||||||
|
from PIL import Image |
||||||
|
|
||||||
|
APP_ICON = os.path.join( |
||||||
|
os.path.abspath( os.path.dirname( __file__ ) ), |
||||||
|
"../vasl_templates/webapp/static/images/app.ico" |
||||||
|
) |
||||||
|
|
||||||
|
# --------------------------------------------------------------------- |
||||||
|
|
||||||
|
def main( args ): |
||||||
|
"""Main processing.""" |
||||||
|
|
||||||
|
# parse the command-line options |
||||||
|
output_fname = "./loader" |
||||||
|
work_dir = os.path.join( tempfile.gettempdir(), "freeze-loader" ) |
||||||
|
cleanup = True |
||||||
|
opts,args = getopt.getopt( args, "o:w:", ["output=","work=","no-clean"] ) |
||||||
|
for opt, val in opts: |
||||||
|
if opt in ["-o","--output"]: |
||||||
|
output_fname = val.strip() |
||||||
|
elif opt in ["-w","--work"]: |
||||||
|
work_dir = val.strip() |
||||||
|
elif opt in ["--no-clean"]: |
||||||
|
cleanup = False |
||||||
|
else: |
||||||
|
raise RuntimeError( "Unknown argument: {}".format( opt ) ) |
||||||
|
|
||||||
|
# freeze the loader program |
||||||
|
freeze_loader( output_fname, work_dir, cleanup ) |
||||||
|
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
||||||
|
|
||||||
|
def freeze_loader( output_fname, work_dir, cleanup ): |
||||||
|
"""Freeze the loader program.""" |
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as dist_dir: |
||||||
|
|
||||||
|
# initialize |
||||||
|
base_dir = os.path.abspath( os.path.dirname( __file__ ) ) |
||||||
|
assets_dir = os.path.join( base_dir, "assets" ) |
||||||
|
|
||||||
|
# convert the app icon to an image |
||||||
|
if not os.path.isdir( work_dir ): |
||||||
|
os.makedirs( work_dir ) |
||||||
|
app_icon_fname = os.path.join( work_dir, "app-icon.png" ) |
||||||
|
_convert_app_icon( app_icon_fname ) |
||||||
|
|
||||||
|
# initialize |
||||||
|
app_name = "loader" |
||||||
|
args = [ |
||||||
|
"--distpath", dist_dir, |
||||||
|
"--workpath", work_dir, |
||||||
|
"--specpath", work_dir, |
||||||
|
"--onefile", |
||||||
|
"--name", app_name, |
||||||
|
] |
||||||
|
args.extend( [ |
||||||
|
"--add-data", app_icon_fname + os.pathsep + "assets/", |
||||||
|
"--add-data", os.path.join(assets_dir,"loading.gif") + os.pathsep + "assets/" |
||||||
|
] ) |
||||||
|
if sys.platform == "win32": |
||||||
|
args.append( "--noconsole" ) |
||||||
|
args.extend( [ "--icon", APP_ICON ] ) |
||||||
|
args.append( os.path.join( base_dir, "main.py" ) ) |
||||||
|
|
||||||
|
# freeze the program |
||||||
|
run_pyinstaller( args ) |
||||||
|
|
||||||
|
# save the generated artifact |
||||||
|
fname = app_name+".exe" if sys.platform == "win32" else app_name |
||||||
|
shutil.move( |
||||||
|
os.path.join( dist_dir, fname ), |
||||||
|
output_fname |
||||||
|
) |
||||||
|
|
||||||
|
# clean up |
||||||
|
if cleanup: |
||||||
|
shutil.rmtree( work_dir ) |
||||||
|
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
||||||
|
|
||||||
|
def _convert_app_icon( save_fname ): |
||||||
|
"""Convert the app icon to an image.""" |
||||||
|
# NOTE: Tkinter's PhotoImage doesn't handle .ico files, so we convert the app icon |
||||||
|
# to an image, then insert it into the PyInstaller-generated executable (so that |
||||||
|
# we don't have to bundle Pillow into the release). |
||||||
|
img = Image.open( APP_ICON ) |
||||||
|
img = img.convert( "RGBA" ).resize( (48, 48) ) |
||||||
|
img.save( save_fname, "png" ) |
||||||
|
|
||||||
|
# --------------------------------------------------------------------- |
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
main( sys.argv[1:] ) |
@ -0,0 +1,207 @@ |
|||||||
|
""" Load the main vasl-templates program. |
||||||
|
|
||||||
|
vasl-templates can be slow to start (especially on Windows), since it has to unpack the PyInstaller-generated EXE, |
||||||
|
then startup Qt. We want to show a splash screen while all this happening, but we can't just put it in vasl-templates, |
||||||
|
since it would only happen *after* all the slow stuff has finished :-/ So, we have this stub program that shows |
||||||
|
a splash screen, launches the main vasl-templates program, and waits for it to finish starting up. |
||||||
|
""" |
||||||
|
|
||||||
|
import sys |
||||||
|
import os |
||||||
|
import subprocess |
||||||
|
import threading |
||||||
|
import itertools |
||||||
|
import urllib.request |
||||||
|
from urllib.error import URLError |
||||||
|
import time |
||||||
|
import configparser |
||||||
|
|
||||||
|
# NOTE: It's important that this program start up quickly (otherwise it becomes pointless), |
||||||
|
# so we use tkinter, instead of PyQt (and also avoid bundling a 2nd copy of PyQt :-/). |
||||||
|
import tkinter |
||||||
|
import tkinter.messagebox |
||||||
|
|
||||||
|
if getattr( sys, "frozen", False ): |
||||||
|
BASE_DIR = sys._MEIPASS #pylint: disable=no-member,protected-access |
||||||
|
else: |
||||||
|
BASE_DIR = os.path.abspath( os.path.dirname( __file__ ) ) |
||||||
|
|
||||||
|
STARTUP_TIMEOUT = 60 # how to long to wait for vasl-templates to start (seconds) |
||||||
|
|
||||||
|
main_window = None |
||||||
|
|
||||||
|
# --------------------------------------------------------------------- |
||||||
|
|
||||||
|
def main( args ): |
||||||
|
"""Load the main vasl-templates program.""" |
||||||
|
|
||||||
|
# initialize Tkinter |
||||||
|
global main_window |
||||||
|
main_window = tkinter.Tk() |
||||||
|
main_window.option_add( "*Dialog.msg.font", "Helvetica 12" ) |
||||||
|
|
||||||
|
# load the app icon |
||||||
|
# NOTE: This image file doesn't exist in source control, but is created dynamically from |
||||||
|
# the main app icon by the freeze script, and inserted into the PyInstaller-generated executable. |
||||||
|
# We do things this way so that we don't have to bundle Pillow into the release. |
||||||
|
app_icon = tkinter.PhotoImage( |
||||||
|
file = make_asset_path( "app-icon.png" ) |
||||||
|
) |
||||||
|
|
||||||
|
# locate the main vasl-templates executable |
||||||
|
fname = os.path.join( os.path.dirname( sys.executable ), "vasl-templates-main" ) |
||||||
|
if sys.platform == "win32": |
||||||
|
fname += ".exe" |
||||||
|
if not os.path.isfile( fname ): |
||||||
|
show_error_msg( "Can't find the main vasl-templates program.", withdraw=True ) |
||||||
|
return -1 |
||||||
|
|
||||||
|
# launch the main vasl-templates program |
||||||
|
try: |
||||||
|
proc = subprocess.Popen( itertools.chain( [fname], args ) ) #pylint: disable=consider-using-with |
||||||
|
except Exception as ex: #pylint: disable=broad-except |
||||||
|
show_error_msg( "Can't start vasl-templates:\n\n{}".format( ex ), withdraw=True ) |
||||||
|
return -2 |
||||||
|
|
||||||
|
# get the webapp port number |
||||||
|
port = 5010 |
||||||
|
fname = os.path.join( os.path.dirname( fname ), "config/app.cfg" ) |
||||||
|
if os.path.isfile( fname ): |
||||||
|
config_parser = configparser.ConfigParser() |
||||||
|
config_parser.optionxform = str # preserve case for the keys :-/ |
||||||
|
config_parser.read( fname ) |
||||||
|
args = dict( config_parser.items( "System" ) ) |
||||||
|
port = args.get( "FLASK_PORT_NO", port ) |
||||||
|
|
||||||
|
# create the splash window |
||||||
|
create_window( app_icon ) |
||||||
|
|
||||||
|
# start a background thread to check on the main vasl-templates process |
||||||
|
threading.Thread( |
||||||
|
target = check_startup, |
||||||
|
args = ( proc, port ) |
||||||
|
).start() |
||||||
|
|
||||||
|
# run the main loop |
||||||
|
main_window.mainloop() |
||||||
|
|
||||||
|
return 0 |
||||||
|
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
||||||
|
|
||||||
|
def create_window( app_icon ): |
||||||
|
"""Create the splash window.""" |
||||||
|
|
||||||
|
# create the splash window |
||||||
|
main_window.geometry( "275x64" ) |
||||||
|
main_window.title( "vasl-templates loader" ) |
||||||
|
main_window.overrideredirect( 1 ) # nb: "-type splash" doesn't work on Windows :-/ |
||||||
|
main_window.eval( "tk::PlaceWindow . center" ) |
||||||
|
main_window.wm_attributes( "-topmost", 1 ) |
||||||
|
main_window.tk.call( "wm", "iconphoto", main_window._w, app_icon ) #pylint: disable=protected-access |
||||||
|
main_window.protocol( "WM_DELETE_WINDOW", lambda: None ) |
||||||
|
|
||||||
|
# add the app icon |
||||||
|
label = tkinter.Label( main_window, image=app_icon ) |
||||||
|
label.grid( row=0, column=0, rowspan=2, padx=8, pady=8 ) |
||||||
|
|
||||||
|
# add the caption |
||||||
|
label = tkinter.Label( main_window, text="Loading vasl-templates...", font=("Helvetica",12) ) |
||||||
|
label.grid( row=0, column=1, padx=5, pady=(8,0) ) |
||||||
|
|
||||||
|
# add the "loading" image (we have to animate it ourself :-/) |
||||||
|
anim_label = tkinter.Label( main_window ) |
||||||
|
anim_label.grid( row=1, column=1, sticky=tkinter.N, padx=0, pady=0 ) |
||||||
|
fname = make_asset_path( "loading.gif" ) |
||||||
|
nframes = 13 |
||||||
|
frames = [ |
||||||
|
tkinter.PhotoImage( file=fname, format="gif -index {}".format( i ) ) |
||||||
|
for i in range(nframes) |
||||||
|
] |
||||||
|
frame_index = 0 |
||||||
|
def next_frame(): |
||||||
|
nonlocal frame_index |
||||||
|
frame = frames[ frame_index ] |
||||||
|
frame_index = ( frame_index + 1 ) % nframes |
||||||
|
anim_label.configure( image=frame ) |
||||||
|
main_window.after( 75, next_frame ) |
||||||
|
main_window.after( 0, next_frame ) |
||||||
|
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
||||||
|
|
||||||
|
def check_startup( proc, port ): |
||||||
|
"""Check the startup of the main vasl-templates process.""" |
||||||
|
|
||||||
|
def do_check(): |
||||||
|
|
||||||
|
# check if we've waited for too long |
||||||
|
if time.time() - start_time > STARTUP_TIMEOUT: |
||||||
|
# yup - give up |
||||||
|
raise RuntimeError( "Couldn't start vasl-templates." ) |
||||||
|
|
||||||
|
# check if the main vasl-templates process has gone away |
||||||
|
if proc.poll() is not None: |
||||||
|
raise RuntimeError( "The vasl-templates program ended unexpectedly." ) |
||||||
|
|
||||||
|
# check if the webapp is responding |
||||||
|
url = "http://localhost:{}/ping".format( port ) |
||||||
|
try: |
||||||
|
with urllib.request.urlopen( url ) as resp: |
||||||
|
_ = resp.read() |
||||||
|
except URLError: |
||||||
|
# no response - the webapp is probably still starting up |
||||||
|
return False |
||||||
|
except Exception as ex: #pylint: disable=broad-except |
||||||
|
raise RuntimeError( "Couldn't communicate with vasl-templates:\n\n{}".format( ex ) ) from ex |
||||||
|
|
||||||
|
# the main vasl-templates program has started up and is responsive - our job is done! |
||||||
|
if sys.platform == "win32": |
||||||
|
# FUDGE! There is a short amount of time between the webapp server starting and |
||||||
|
# the main window appearing. We delay here for a bit, to try to synchronize |
||||||
|
# our window fading out with the main vasl-templates window appearing. |
||||||
|
time.sleep( 1 ) |
||||||
|
return True |
||||||
|
|
||||||
|
def on_done( msg ): |
||||||
|
if msg: |
||||||
|
show_error_msg( msg, withdraw=True ) |
||||||
|
fade_out( main_window, main_window.quit ) |
||||||
|
|
||||||
|
# run the main loop |
||||||
|
start_time = time.time() |
||||||
|
while True: |
||||||
|
try: |
||||||
|
if do_check(): |
||||||
|
on_done( None ) |
||||||
|
break |
||||||
|
except Exception as ex: #pylint: disable=broad-except |
||||||
|
on_done( str(ex) ) |
||||||
|
return |
||||||
|
time.sleep( 0.25 ) |
||||||
|
|
||||||
|
# --------------------------------------------------------------------- |
||||||
|
|
||||||
|
def fade_out( target, on_done ): |
||||||
|
"""Fade out the target window.""" |
||||||
|
alpha = target.attributes( "-alpha" ) |
||||||
|
if alpha > 0: |
||||||
|
alpha -= 0.1 |
||||||
|
target.attributes( "-alpha", alpha ) |
||||||
|
target.after( 50, lambda: fade_out( target, on_done ) ) |
||||||
|
else: |
||||||
|
on_done() |
||||||
|
|
||||||
|
def make_asset_path( fname ): |
||||||
|
"""Generate the path to an asset file.""" |
||||||
|
return os.path.join( BASE_DIR, "assets", fname ) |
||||||
|
|
||||||
|
def show_error_msg( error_msg, withdraw=False ): |
||||||
|
"""Show an error dialog.""" |
||||||
|
if withdraw: |
||||||
|
main_window.withdraw() |
||||||
|
tkinter.messagebox.showinfo( "vasl-templates loader error", error_msg ) |
||||||
|
|
||||||
|
# --------------------------------------------------------------------- |
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
sys.exit( main( sys.argv[1:] ) ) |
@ -1,7 +1,7 @@ |
|||||||
pytest==6.2.1 |
pytest==7.4.2 |
||||||
grpcio-tools==1.34.1 |
grpcio-tools==1.58.0 |
||||||
tabulate==0.8.7 |
tabulate==0.9.0 |
||||||
lxml==4.6.2 |
lxml==4.9.3 |
||||||
pylint==2.6.0 |
pylint==2.17.5 |
||||||
pytest-pylint==0.18.0 |
pytest-pylint==0.19.0 |
||||||
pyinstaller==4.2 |
pyinstaller==5.13.2 |
||||||
|
@ -1,7 +1,10 @@ |
|||||||
# python 3.8.7 |
# python 3.11.4 |
||||||
|
|
||||||
flask==1.1.2 |
flask==2.3.3 |
||||||
pyyaml==5.3.1 |
pyyaml==6.0.1 |
||||||
pillow==8.1.0 |
# NOTE: Pillow 9.5.0 is the last version that provides 32-bit wheels. |
||||||
selenium==3.141.0 |
pillow==9.5.0 |
||||||
click==7.1.2 |
selenium==4.12.0 |
||||||
|
waitress==2.1.2 |
||||||
|
appdirs==1.4.4 |
||||||
|
click==8.1.7 |
||||||
|
@ -0,0 +1,83 @@ |
|||||||
|
#!/usr/bin/env python3 |
||||||
|
""" Prepare the piece info for a VASL module. |
||||||
|
|
||||||
|
The main program used to identify 5/8" counters by reading a module's buildFile and checking the height |
||||||
|
attribute of the PieceSlot nodes, but it turns out this is the wrong thing to do (this field actually |
||||||
|
controls the size of the piece's entry in the counter palette): |
||||||
|
https://github.com/vasl-developers/vasl/issues/1195 |
||||||
|
|
||||||
|
For each version of VASL supported, run vassal-shim (getPieceInfo command) to analyze the module's |
||||||
|
buildFile and get the correct counter sizes. Then pass the output into this script, to generate |
||||||
|
the final data file that should be saved in the $/data/vasl-$VERSION/ directory, where it will |
||||||
|
be read by the main program. |
||||||
|
|
||||||
|
NOTE: Introducing this process opens the possibility of also extracting the image file paths |
||||||
|
within the .vmod file, instead of the current messy parsing of the PieceSlot CDATA... :-/ |
||||||
|
""" |
||||||
|
|
||||||
|
import sys |
||||||
|
import os |
||||||
|
import json |
||||||
|
|
||||||
|
import xml.etree.ElementTree as ET |
||||||
|
|
||||||
|
# --------------------------------------------------------------------- |
||||||
|
|
||||||
|
# initialize |
||||||
|
report = {} |
||||||
|
|
||||||
|
# figure out which GPID's we're interested in |
||||||
|
gpids = set() |
||||||
|
def get_gpids( vo_type ): |
||||||
|
"""Get the GPID's from our data files.""" |
||||||
|
dname = os.path.join( os.path.dirname(__file__), "../webapp/data", vo_type ) |
||||||
|
for root,_,fnames in os.walk( dname ): |
||||||
|
for fname in fnames: |
||||||
|
if os.path.splitext( fname )[1] != ".json": |
||||||
|
continue |
||||||
|
fname = os.path.join( root, fname ) |
||||||
|
with open( fname, "r", encoding="utf-8" ) as fp: |
||||||
|
entries = json.load( fp ) |
||||||
|
for entry in entries: |
||||||
|
entry_gpid = entry.get( "gpid" ) |
||||||
|
if not entry_gpid: |
||||||
|
continue |
||||||
|
if isinstance( entry_gpid, list ): |
||||||
|
gpids.update( str(g) for g in entry_gpid ) |
||||||
|
else: |
||||||
|
gpids.add( str( entry_gpid ) ) |
||||||
|
get_gpids( "vehicles" ) |
||||||
|
get_gpids( "ordnance" ) |
||||||
|
|
||||||
|
# parse the piece info generated by vassal-shim |
||||||
|
doc = ET.parse( sys.stdin ) |
||||||
|
for piece_info in doc.getroot(): |
||||||
|
gpid = piece_info.attrib["gpid"] |
||||||
|
if gpid not in gpids: |
||||||
|
continue |
||||||
|
info = {} |
||||||
|
# check if the next piece is small |
||||||
|
# FUDGE! We used to check for <= 48, but what we get is GamePiece.boundingBox(), which is |
||||||
|
# the click zone for the counter, not the actual size of the counter's image :-/ |
||||||
|
if int( piece_info.attrib["height"] ) <= 55: |
||||||
|
info["is_small"] = True |
||||||
|
if info: |
||||||
|
report[ gpid ] = info |
||||||
|
|
||||||
|
# FUDGE! These are from extensions - it's not worth trying to figure these out programtically. |
||||||
|
report[ "adf:1948" ] = { "is_small": True } # BFP Blood & Jungle: Dutch Brandt 47mm Mortar |
||||||
|
report[ "adf:75" ] = { "is_small": True } # BFP Blood & Jungle: Indonesian Type 89 Heavy Grenade Launcher |
||||||
|
report[ "adf:77" ] = { "is_small": True } # BFP Blood & Jungle: Indonesian Type 97 Automatic Gun |
||||||
|
report[ "adf:76" ] = { "is_small": True } # BFP Blood & Jungle: Indonesian Year-11 Flat-Trajectory INF Gun |
||||||
|
report[ "adf:1407" ] = { "is_small": True } # BFP Poland In Flames: German 2cm Tankbusche S-18 |
||||||
|
report[ "08d:75" ] = { "is_small": True } # Fight For Seoul: American M20(L) 75mm Recoilless Rifle |
||||||
|
|
||||||
|
# output the final report |
||||||
|
print( "{" ) |
||||||
|
lines = [] |
||||||
|
for gpid, piece_info in report.items(): |
||||||
|
lines.append( "\"{}\": {}".format( |
||||||
|
gpid, json.dumps( piece_info ) |
||||||
|
) ) |
||||||
|
print( ",\n".join( lines ) ) |
||||||
|
print( "}" ) |
@ -0,0 +1,5 @@ |
|||||||
|
<html> <!-- vasl-templates:id {{SNIPPET_ID}} --> |
||||||
|
|
||||||
|
<img src="{{IMAGES_BASE_URL}}/compass/{{COMPASS}}.png"> |
||||||
|
|
||||||
|
</html> |
@ -0,0 +1,41 @@ |
|||||||
|
<html> <!-- vasl-templates:id {{SNIPPET_ID}} --> |
||||||
|
|
||||||
|
<!-- vasl-templates:name Booby Traps --> |
||||||
|
<!-- vasl-templates:description Data chart for Booby Traps. --> |
||||||
|
|
||||||
|
<!-- player = {{PLAYER_DROPLIST:|Player}} |
||||||
|
<!-- boards = {{BOARDS*:/8|Board(s)}} --> |
||||||
|
|
||||||
|
<head> |
||||||
|
<meta charset="utf-8"> |
||||||
|
<style> |
||||||
|
.header { |
||||||
|
background: {{PLAYER_COLORS[PLAYER_DROPLIST][0]}} ; |
||||||
|
border-bottom: 1px solid {{PLAYER_COLORS[PLAYER_DROPLIST][2]}} ; |
||||||
|
padding: 2px 5px ; |
||||||
|
font-size: 105% ; font-weight: bold ; |
||||||
|
} |
||||||
|
.header .level { font-size: 90% ; font-style: italic ; } |
||||||
|
{{CSS:common}} |
||||||
|
</style> |
||||||
|
</head> |
||||||
|
|
||||||
|
<table> |
||||||
|
|
||||||
|
<tr> |
||||||
|
<td class="header"> |
||||||
|
<img src="{{PLAYER_FLAGS[PLAYER_DROPLIST]}}?prefh={{PLAYER_FLAG_SIZE_LARGE}}" width="{{PLAYER_FLAG_SIZE_LARGE}}" height="{{PLAYER_FLAG_SIZE_LARGE}}"> Booby Traps <span class="level">(Level {{LEVEL:A::B::C/3|Level}})</span> |
||||||
|
|
||||||
|
<tr> |
||||||
|
<td style="padding:2px 5px;"> |
||||||
|
<b> {%if BOARDS%} Boards: {{BOARDS}} {%else%} Entire map {%endif%} </b> |
||||||
|
<ul> |
||||||
|
<li> Original TC |
||||||
|
{% if LEVEL == "A" %} ≥ 11 |
||||||
|
{% elif LEVEL == "B" %} 11 |
||||||
|
{% elif LEVEL == "C" %} 12 |
||||||
|
{%else%} ??? {%endif%} |
||||||
|
<li> Search Casualties |
||||||
|
</ul> |
||||||
|
|
||||||
|
</table> |
@ -0,0 +1,87 @@ |
|||||||
|
<html> <!-- vasl-templates:id {{SNIPPET_ID}} --> |
||||||
|
|
||||||
|
<!-- vasl-templates:name Kampfgruppe Scherer --> |
||||||
|
<!-- vasl-templates:description Data charts for Grenade Bundles and Molotov Cocktails. --> |
||||||
|
<!-- {{TYPE:Grenade Bundles::Molotov Cocktails/10|Data chart}} --> |
||||||
|
|
||||||
|
<head> |
||||||
|
<meta charset="utf-8"> |
||||||
|
<style> {{CSS:common}} </style> |
||||||
|
</head> |
||||||
|
|
||||||
|
<table> |
||||||
|
|
||||||
|
<tr> |
||||||
|
<td colspan="2" style=" |
||||||
|
background: {{PLAYER_COLORS["german"][0]}} ; |
||||||
|
border-bottom: 1px solid {{PLAYER_COLORS["german"][2]}} ; |
||||||
|
padding: 2px 5px ; |
||||||
|
font-size: 105% ; font-weight: bold ; |
||||||
|
"> |
||||||
|
{# Some versions of Java require <img> tags to have the width and height specified!?! #} |
||||||
|
{%if PLAYER_FLAGS["german"]%}<img src="{{PLAYER_FLAGS["german"]}}?prefh={{PLAYER_FLAG_SIZE_LARGE}}" width="{{PLAYER_FLAG_SIZE_LARGE}}" height="{{PLAYER_FLAG_SIZE_LARGE}}"> {%endif%}{{TYPE}} |
||||||
|
|
||||||
|
{% if TYPE == "Grenade Bundles" %} |
||||||
|
|
||||||
|
<tr> |
||||||
|
<td style="padding:3px 5px 0 5px;"> |
||||||
|
CC Attack -2 DRM |
||||||
|
|
||||||
|
<tr> |
||||||
|
<td style="padding:3px 5px 0 5px;"> |
||||||
|
<b>ATMM check</b>: dr ≤ 3 (△) |
||||||
|
<table style="margin-left:10px;"> |
||||||
|
<tr> |
||||||
|
<td style="width:20px;"> +1 |
||||||
|
<td> HS/crew |
||||||
|
<tr> |
||||||
|
<td> +2 |
||||||
|
<td> SMC |
||||||
|
<tr> |
||||||
|
<td> +1 |
||||||
|
<td> CX |
||||||
|
<tr> |
||||||
|
<td> +1 |
||||||
|
<td> vs. non-armored vehicle |
||||||
|
</table> |
||||||
|
original 6 = pinned (CCV reduced by 1) |
||||||
|
|
||||||
|
{% elif TYPE == "Molotov Cocktails" %} |
||||||
|
|
||||||
|
<tr> |
||||||
|
<td style="padding:3px 5px 0 5px;"> |
||||||
|
Against AFV only. |
||||||
|
|
||||||
|
<tr> |
||||||
|
<td style="padding:3px 5px 0 5px;"> |
||||||
|
<b>MOL check</b>: dr ≤ 3 (△) |
||||||
|
<table style="margin-left:10px;"> |
||||||
|
<tr> |
||||||
|
<td style="width:20px;"> +1 |
||||||
|
<td> HS/crew |
||||||
|
<tr> |
||||||
|
<td> +2 |
||||||
|
<td> SMC |
||||||
|
<tr> |
||||||
|
<td> +1 |
||||||
|
<td> CX |
||||||
|
</table> |
||||||
|
|
||||||
|
<tr> |
||||||
|
<td style="padding:3px 5px 0 5px;"> |
||||||
|
<b>IFT DR original colored dr</b>: |
||||||
|
<ul> |
||||||
|
<li> 1 = Flame in target Location |
||||||
|
<li> 6 = thrower breaks, Flame in their Location |
||||||
|
</ul> |
||||||
|
|
||||||
|
<tr> |
||||||
|
<td style="padding:3px 5px 0 5px;"> |
||||||
|
<b>Kindling Attempt</b>: +2 DRM |
||||||
|
|
||||||
|
{%endif%} |
||||||
|
|
||||||
|
</table> |
||||||
|
|
||||||
|
</html> |
||||||
|
|
@ -1,49 +0,0 @@ |
|||||||
<html> <!-- vasl-templates:id {{SNIPPET_ID}} --> |
|
||||||
|
|
||||||
<!-- vasl-templates:name KGS Grenade Bundles --> |
|
||||||
<!-- vasl-templates:description Data chart for Grenade Bundles in <i>Kampfgruppe Scherer</i>. --> |
|
||||||
|
|
||||||
<head> |
|
||||||
<meta charset="utf-8"> |
|
||||||
<style> {{CSS:common}} </style> |
|
||||||
</head> |
|
||||||
|
|
||||||
<table> |
|
||||||
|
|
||||||
<tr> |
|
||||||
<td colspan="2" style=" |
|
||||||
background: {{PLAYER_COLORS["german"][0]}} ; |
|
||||||
border-bottom: 1px solid {{PLAYER_COLORS["german"][2]}} ; |
|
||||||
padding: 2px 5px ; |
|
||||||
font-size: 105% ; font-weight: bold ; |
|
||||||
"> |
|
||||||
{# Some versions of Java require <img> tags to have the width and height specified!?! #} |
|
||||||
{%if PLAYER_FLAGS["german"]%}<img src="{{PLAYER_FLAGS["german"]}}" {{PLAYER_FLAG_SIZE_LARGE}}> {%endif%}Grenade Bundles |
|
||||||
|
|
||||||
<tr> |
|
||||||
<td style="padding:3px 5px 0 5px;"> |
|
||||||
-2 CC Attack DRM |
|
||||||
|
|
||||||
<tr> |
|
||||||
<td style="padding:3px 5px 0 5px;"> |
|
||||||
ATMM check: dr ≤ 3 (△) |
|
||||||
<table style="margin-left:10px;"> |
|
||||||
<tr> |
|
||||||
<td style="width:20px;"> +1 |
|
||||||
<td> HS/crew |
|
||||||
<tr> |
|
||||||
<td> +2 |
|
||||||
<td> SMC |
|
||||||
<tr> |
|
||||||
<td> +1 |
|
||||||
<td> CX |
|
||||||
<tr> |
|
||||||
<td> +1 |
|
||||||
<td> vs. non-armored vehicle |
|
||||||
</table> |
|
||||||
original 6 = pinned (CCV reduced by 1) |
|
||||||
|
|
||||||
</table> |
|
||||||
|
|
||||||
</html> |
|
||||||
|
|
@ -1,57 +0,0 @@ |
|||||||
<html> <!-- vasl-templates:id {{SNIPPET_ID}} --> |
|
||||||
|
|
||||||
<!-- vasl-templates:name KGS Molotov Cocktails --> |
|
||||||
<!-- vasl-templates:description Data chart for Molotov Cocktails in <i>Kampfgruppe Scherer</i>. --> |
|
||||||
|
|
||||||
<head> |
|
||||||
<meta charset="utf-8"> |
|
||||||
<style> {{CSS:common}} </style> |
|
||||||
</head> |
|
||||||
|
|
||||||
<table> |
|
||||||
|
|
||||||
<tr> |
|
||||||
<td colspan="2" style=" |
|
||||||
background: {{PLAYER_COLORS["german"][0]}} ; |
|
||||||
border-bottom: 1px solid {{PLAYER_COLORS["german"][2]}} ; |
|
||||||
padding: 2px 5px ; |
|
||||||
font-size: 105% ; font-weight: bold ; |
|
||||||
"> |
|
||||||
{# Some versions of Java require <img> tags to have the width and height specified!?! #} |
|
||||||
{%if PLAYER_FLAGS["german"]%}<img src="{{PLAYER_FLAGS["german"]}}" {{PLAYER_FLAG_SIZE_LARGE}}> {%endif%}Molotov Cocktails |
|
||||||
|
|
||||||
<tr> |
|
||||||
<td style="padding:3px 5px 0 5px;"> |
|
||||||
vs. AFV only |
|
||||||
|
|
||||||
<tr> |
|
||||||
<td style="padding:3px 5px 0 5px;"> |
|
||||||
MOL check: dr ≤ 3 (△) |
|
||||||
<table style="margin-left:10px;"> |
|
||||||
<tr> |
|
||||||
<td style="width:20px;"> +1 |
|
||||||
<td> HS/crew |
|
||||||
<tr> |
|
||||||
<td> +2 |
|
||||||
<td> SMC |
|
||||||
<tr> |
|
||||||
<td> +1 |
|
||||||
<td> CX |
|
||||||
</table> |
|
||||||
|
|
||||||
<tr> |
|
||||||
<td style="padding:3px 5px 0 5px;"> |
|
||||||
IFT DR original colored dr: |
|
||||||
<ul> |
|
||||||
<li> 1 = Flame in target Location |
|
||||||
<li> 6 = thrower breaks, Flame in their Location |
|
||||||
</ul> |
|
||||||
|
|
||||||
<tr> |
|
||||||
<td style="padding:3px 5px 0 5px;"> |
|
||||||
Kindling Attempt: +2 DRM |
|
||||||
|
|
||||||
</table> |
|
||||||
|
|
||||||
</html> |
|
||||||
|
|
@ -1,2 +1,2 @@ |
|||||||
{# Some versions of Java require <img> tags to have the width and height specified!?! #} |
{# Some versions of Java require <img> tags to have the width and height specified!?! #} |
||||||
{%if PLAYER_FLAG%}<img src="{{PLAYER_FLAG}}" {{PLAYER_FLAG_SIZE}}> {%endif%} |
{%if PLAYER_FLAG%}<img src="{{PLAYER_FLAG}}?prefh={{PLAYER_FLAG_SIZE}}" width="{{PLAYER_FLAG_SIZE}}" height="{{PLAYER_FLAG_SIZE}}"> {%endif%} |
||||||
|
@ -1,2 +1,2 @@ |
|||||||
{# Some versions of Java require <img> tags to have the width and height specified!?! #} |
{# Some versions of Java require <img> tags to have the width and height specified!?! #} |
||||||
{%if PLAYER_FLAG%}<img src="{{PLAYER_FLAG}}" {{PLAYER_FLAG_SIZE_LARGE}}> {%endif%} |
{%if PLAYER_FLAG%}<img src="{{PLAYER_FLAG}}?prefh={{PLAYER_FLAG_SIZE_LARGE}}" width="{{PLAYER_FLAG_SIZE_LARGE}}" height="{{PLAYER_FLAG_SIZE_LARGE}}"> {%endif%} |
||||||
|
@ -0,0 +1,116 @@ |
|||||||
|
<html> <!-- vasl-templates:id {{SNIPPET_ID}} --> |
||||||
|
|
||||||
|
<head> |
||||||
|
<meta charset="utf-8"> |
||||||
|
<style> {{CSS:common}} </style> |
||||||
|
|
||||||
|
<style> |
||||||
|
|
||||||
|
td { |
||||||
|
width: 50px ; min-width: 50px ; |
||||||
|
height: {%if TURN_TRACK_PREVIEW_MODE%} 50px {%else%} 43px {%endif%} ; |
||||||
|
padding: 2px ; |
||||||
|
border: 1px solid black ; |
||||||
|
} |
||||||
|
{% set RESET_TD = "min-width: unset ; height: unset ; padding: 0 ; border: none" %} |
||||||
|
td.turn-no { |
||||||
|
{{RESET_TD}} ; width: unset ; |
||||||
|
text-align: center ; vertical-align: center ; font-size: 18px ; font-weight: bold ; |
||||||
|
} |
||||||
|
td.no-reinforce { {{RESET_TD}} ; width: 13px ; } |
||||||
|
{# NOTE: We do the reinforcement flags as CSS backgrounds, since VASSAL is incredibly slow downloading normal images. #} |
||||||
|
td.reinforce1 { {{RESET_TD}} ; width: 13px ; background: url("{{TURN_TRACK_FLAG_1}}") top left no-repeat ; vertical-align: top ; } |
||||||
|
td.reinforce2 { {{RESET_TD}} ; width: 13px ; background: url("{{TURN_TRACK_FLAG_2}}") bottom right no-repeat ; vertical-align: bottom ; } |
||||||
|
td.half-turn { |
||||||
|
background: url("{{TURN_TRACK_HALF_TURN_IMAGE_URL}}") bottom right no-repeat ; |
||||||
|
background-size: contain ; {# nb: doesn't work in VASSAL, the image file needs to be the correct size :-/ #} |
||||||
|
} |
||||||
|
|
||||||
|
{% if TURN_TRACK_PREVIEW_MODE %} |
||||||
|
body { margin: 0 ; } |
||||||
|
body ::selection {} |
||||||
|
body ::moz-selection {} |
||||||
|
body { user-select: none ; } |
||||||
|
.reinforce1, .reinforce2 { opacity: 0 ; } |
||||||
|
.flag-click { width: 13px ; height: 13px ; cursor: pointer ; } |
||||||
|
.shading-click { cursor: pointer ; } |
||||||
|
{%endif%} |
||||||
|
|
||||||
|
</style> |
||||||
|
|
||||||
|
</head> |
||||||
|
|
||||||
|
{% if TURN_TRACK_PREVIEW_MODE %} |
||||||
|
<script> |
||||||
|
// notify the parent window of clicks |
||||||
|
function onFlagClick( turnNo, playerNo ) { |
||||||
|
window.parent.postMessage( { |
||||||
|
type: "FlagClick", |
||||||
|
turnNo: turnNo, uiPlayerNo: playerNo |
||||||
|
}, "*" ) ; |
||||||
|
} |
||||||
|
function onShadingClick( turnNo ) { |
||||||
|
window.parent.postMessage( { |
||||||
|
type: "ShadingClick", |
||||||
|
turnNo: turnNo |
||||||
|
}, "*" ) ; |
||||||
|
} |
||||||
|
</script> |
||||||
|
{%endif%} |
||||||
|
|
||||||
|
<table class="turn-track"> |
||||||
|
|
||||||
|
{% for row in TURN_TRACK_SQUARES %} |
||||||
|
<tr> |
||||||
|
|
||||||
|
{% for turnSquare in row %} |
||||||
|
<td id="turn-square-{{turnSquare[0]}}" |
||||||
|
{%if turnSquare[0] == TURN_TRACK_HALF_TURN%} class="half-turn" {%endif%} |
||||||
|
{% if turnSquare[3] %} style="background-color:{{turnSquare[3]}};" {%endif%} |
||||||
|
> |
||||||
|
|
||||||
|
<table style="width:100%;height:100%;"> <tr> |
||||||
|
|
||||||
|
<td id="flag-{{turnSquare[0]}}_1" width="100%" |
||||||
|
class = {% if turnSquare[1] %} "reinforce1" {%else%} "no-reinforce" {%endif%} |
||||||
|
> |
||||||
|
{% if TURN_TRACK_PREVIEW_MODE %} |
||||||
|
<div class="flag-click" |
||||||
|
onclick = "onFlagClick( {{turnSquare[0]}}, 1 )" |
||||||
|
> </div> |
||||||
|
{%endif%} |
||||||
|
</td> |
||||||
|
|
||||||
|
<td class="turn-no"> |
||||||
|
{% if TURN_TRACK_PREVIEW_MODE %} |
||||||
|
<div class="shading-click" |
||||||
|
onclick = "onShadingClick( {{turnSquare[0]}} )" |
||||||
|
> |
||||||
|
{{turnSquare[0]}} |
||||||
|
</div> |
||||||
|
{%else%} |
||||||
|
{{turnSquare[0]}} |
||||||
|
{%endif%} |
||||||
|
</td> |
||||||
|
|
||||||
|
<td id="flag-{{turnSquare[0]}}_2" width="100%" |
||||||
|
class = {% if turnSquare[2] and turnSquare[0] != TURN_TRACK_HALF_TURN %} "reinforce2" {%else%} "no-reinforce" {%endif%} |
||||||
|
> |
||||||
|
{% if TURN_TRACK_PREVIEW_MODE and turnSquare[0] != TURN_TRACK_HALF_TURN %} |
||||||
|
<div class="flag-click" |
||||||
|
onclick = "onFlagClick( {{turnSquare[0]}}, 2 )" |
||||||
|
> </div> |
||||||
|
{%endif%} |
||||||
|
</td> |
||||||
|
|
||||||
|
</tr> </table> |
||||||
|
|
||||||
|
</td> |
||||||
|
{%endfor%} |
||||||
|
|
||||||
|
</tr> |
||||||
|
{%endfor%} |
||||||
|
|
||||||
|
</table> |
||||||
|
|
||||||
|
</html> |
@ -0,0 +1,26 @@ |
|||||||
|
[ |
||||||
|
|
||||||
|
{ "name": "81mm Granatkastare m/29", |
||||||
|
"type": "MTR", |
||||||
|
"capabilities2": { "s": 8 }, |
||||||
|
"comments": [ "QSU" ], |
||||||
|
"note_number": "1", |
||||||
|
"id": "swe/o:000", |
||||||
|
"gpid": 13832 |
||||||
|
}, |
||||||
|
{ "name": "37mm Pansarvärnskanon m/38", |
||||||
|
"type": "AT", |
||||||
|
"comments": [ "QSU" ], |
||||||
|
"note_number": "2", |
||||||
|
"id": "swe/o:001", |
||||||
|
"gpid": 13835 |
||||||
|
}, |
||||||
|
{ "name": "8.4cm Feltkanon m/1887", |
||||||
|
"type": "ART", |
||||||
|
"comments": [ "QSU", "No Gunshield", "Acquisition NA" ], |
||||||
|
"note_number": "3", |
||||||
|
"id": "swe/o:002", |
||||||
|
"gpid": 13836 |
||||||
|
} |
||||||
|
|
||||||
|
] |
@ -0,0 +1,65 @@ |
|||||||
|
{ |
||||||
|
"6996": {"is_small": true}, |
||||||
|
"485": {"is_small": true}, |
||||||
|
"850": {"is_small": true}, |
||||||
|
"849": {"is_small": true}, |
||||||
|
"12689": {"is_small": true}, |
||||||
|
"856": {"is_small": true}, |
||||||
|
"857": {"is_small": true}, |
||||||
|
"11336": {"is_small": true}, |
||||||
|
"858": {"is_small": true}, |
||||||
|
"11337": {"is_small": true}, |
||||||
|
"1149": {"is_small": true}, |
||||||
|
"1153": {"is_small": true}, |
||||||
|
"12687": {"is_small": true}, |
||||||
|
"3b5:7613": {"is_small": true}, |
||||||
|
"11359": {"is_small": true}, |
||||||
|
"3b5:11259": {"is_small": true}, |
||||||
|
"1632": {"is_small": true}, |
||||||
|
"1636": {"is_small": true}, |
||||||
|
"1641": {"is_small": true}, |
||||||
|
"1648": {"is_small": true}, |
||||||
|
"1982": {"is_small": true}, |
||||||
|
"1983": {"is_small": true}, |
||||||
|
"1984": {"is_small": true}, |
||||||
|
"1985": {"is_small": true}, |
||||||
|
"1986": {"is_small": true}, |
||||||
|
"1987": {"is_small": true}, |
||||||
|
"1988": {"is_small": true}, |
||||||
|
"2172": {"is_small": true}, |
||||||
|
"2173": {"is_small": true}, |
||||||
|
"2176": {"is_small": true}, |
||||||
|
"2179": {"is_small": true}, |
||||||
|
"11391": {"is_small": true}, |
||||||
|
"11392": {"is_small": true}, |
||||||
|
"11395": {"is_small": true}, |
||||||
|
"11396": {"is_small": true}, |
||||||
|
"11440": {"is_small": true}, |
||||||
|
"3b5:8401": {"is_small": true}, |
||||||
|
"3b5:8402": {"is_small": true}, |
||||||
|
"2465": {"is_small": true}, |
||||||
|
"2474": {"is_small": true}, |
||||||
|
"3252": {"is_small": true}, |
||||||
|
"3253": {"is_small": true}, |
||||||
|
"3263": {"is_small": true}, |
||||||
|
"3422": {"is_small": true}, |
||||||
|
"3428": {"is_small": true}, |
||||||
|
"6730": {"is_small": true}, |
||||||
|
"3605": {"is_small": true}, |
||||||
|
"3608": {"is_small": true}, |
||||||
|
"6763": {"is_small": true}, |
||||||
|
"3679": {"is_small": true}, |
||||||
|
"3680": {"is_small": true}, |
||||||
|
"3681": {"is_small": true}, |
||||||
|
"3682": {"is_small": true}, |
||||||
|
"3691": {"is_small": true}, |
||||||
|
"3692": {"is_small": true}, |
||||||
|
"3959": {"is_small": true}, |
||||||
|
"11558": {"is_small": true}, |
||||||
|
"11559": {"is_small": true}, |
||||||
|
"3b5:10150": {"is_small": true}, |
||||||
|
"3b5:10151": {"is_small": true}, |
||||||
|
"11600": {"is_small": true}, |
||||||
|
"11604": {"is_small": true}, |
||||||
|
"3b5:7871": {"is_small": true} |
||||||
|
} |
@ -0,0 +1,65 @@ |
|||||||
|
{ |
||||||
|
"6996": {"is_small": true}, |
||||||
|
"485": {"is_small": true}, |
||||||
|
"850": {"is_small": true}, |
||||||
|
"849": {"is_small": true}, |
||||||
|
"12689": {"is_small": true}, |
||||||
|
"856": {"is_small": true}, |
||||||
|
"857": {"is_small": true}, |
||||||
|
"11336": {"is_small": true}, |
||||||
|
"858": {"is_small": true}, |
||||||
|
"11337": {"is_small": true}, |
||||||
|
"1149": {"is_small": true}, |
||||||
|
"1153": {"is_small": true}, |
||||||
|
"12687": {"is_small": true}, |
||||||
|
"3b5:7613": {"is_small": true}, |
||||||
|
"11359": {"is_small": true}, |
||||||
|
"3b5:11259": {"is_small": true}, |
||||||
|
"1632": {"is_small": true}, |
||||||
|
"1636": {"is_small": true}, |
||||||
|
"1641": {"is_small": true}, |
||||||
|
"1648": {"is_small": true}, |
||||||
|
"1982": {"is_small": true}, |
||||||
|
"1983": {"is_small": true}, |
||||||
|
"1984": {"is_small": true}, |
||||||
|
"1985": {"is_small": true}, |
||||||
|
"1986": {"is_small": true}, |
||||||
|
"1987": {"is_small": true}, |
||||||
|
"1988": {"is_small": true}, |
||||||
|
"2172": {"is_small": true}, |
||||||
|
"2173": {"is_small": true}, |
||||||
|
"2176": {"is_small": true}, |
||||||
|
"2179": {"is_small": true}, |
||||||
|
"11391": {"is_small": true}, |
||||||
|
"11392": {"is_small": true}, |
||||||
|
"11395": {"is_small": true}, |
||||||
|
"11396": {"is_small": true}, |
||||||
|
"11440": {"is_small": true}, |
||||||
|
"3b5:8401": {"is_small": true}, |
||||||
|
"3b5:8402": {"is_small": true}, |
||||||
|
"2465": {"is_small": true}, |
||||||
|
"2474": {"is_small": true}, |
||||||
|
"3252": {"is_small": true}, |
||||||
|
"3253": {"is_small": true}, |
||||||
|
"3263": {"is_small": true}, |
||||||
|
"3422": {"is_small": true}, |
||||||
|
"3428": {"is_small": true}, |
||||||
|
"6730": {"is_small": true}, |
||||||
|
"3605": {"is_small": true}, |
||||||
|
"3608": {"is_small": true}, |
||||||
|
"6763": {"is_small": true}, |
||||||
|
"3679": {"is_small": true}, |
||||||
|
"3680": {"is_small": true}, |
||||||
|
"3681": {"is_small": true}, |
||||||
|
"3682": {"is_small": true}, |
||||||
|
"3691": {"is_small": true}, |
||||||
|
"3692": {"is_small": true}, |
||||||
|
"3959": {"is_small": true}, |
||||||
|
"11558": {"is_small": true}, |
||||||
|
"11559": {"is_small": true}, |
||||||
|
"3b5:10150": {"is_small": true}, |
||||||
|
"3b5:10151": {"is_small": true}, |
||||||
|
"11600": {"is_small": true}, |
||||||
|
"11604": {"is_small": true}, |
||||||
|
"3b5:7871": {"is_small": true} |
||||||
|
} |
@ -0,0 +1,65 @@ |
|||||||
|
{ |
||||||
|
"6996": {"is_small": true}, |
||||||
|
"485": {"is_small": true}, |
||||||
|
"850": {"is_small": true}, |
||||||
|
"849": {"is_small": true}, |
||||||
|
"12689": {"is_small": true}, |
||||||
|
"856": {"is_small": true}, |
||||||
|
"857": {"is_small": true}, |
||||||
|
"11336": {"is_small": true}, |
||||||
|
"858": {"is_small": true}, |
||||||
|
"11337": {"is_small": true}, |
||||||
|
"1149": {"is_small": true}, |
||||||
|
"1153": {"is_small": true}, |
||||||
|
"12687": {"is_small": true}, |
||||||
|
"3b5:7613": {"is_small": true}, |
||||||
|
"11359": {"is_small": true}, |
||||||
|
"3b5:11259": {"is_small": true}, |
||||||
|
"1632": {"is_small": true}, |
||||||
|
"1636": {"is_small": true}, |
||||||
|
"1641": {"is_small": true}, |
||||||
|
"1648": {"is_small": true}, |
||||||
|
"1982": {"is_small": true}, |
||||||
|
"1983": {"is_small": true}, |
||||||
|
"1984": {"is_small": true}, |
||||||
|
"1985": {"is_small": true}, |
||||||
|
"1986": {"is_small": true}, |
||||||
|
"1987": {"is_small": true}, |
||||||
|
"1988": {"is_small": true}, |
||||||
|
"2172": {"is_small": true}, |
||||||
|
"2173": {"is_small": true}, |
||||||
|
"2176": {"is_small": true}, |
||||||
|
"2179": {"is_small": true}, |
||||||
|
"11391": {"is_small": true}, |
||||||
|
"11392": {"is_small": true}, |
||||||
|
"11395": {"is_small": true}, |
||||||
|
"11396": {"is_small": true}, |
||||||
|
"11440": {"is_small": true}, |
||||||
|
"3b5:8401": {"is_small": true}, |
||||||
|
"3b5:8402": {"is_small": true}, |
||||||
|
"2465": {"is_small": true}, |
||||||
|
"2474": {"is_small": true}, |
||||||
|
"3252": {"is_small": true}, |
||||||
|
"3253": {"is_small": true}, |
||||||
|
"3263": {"is_small": true}, |
||||||
|
"3422": {"is_small": true}, |
||||||
|
"3428": {"is_small": true}, |
||||||
|
"6730": {"is_small": true}, |
||||||
|
"3605": {"is_small": true}, |
||||||
|
"3608": {"is_small": true}, |
||||||
|
"6763": {"is_small": true}, |
||||||
|
"3679": {"is_small": true}, |
||||||
|
"3680": {"is_small": true}, |
||||||
|
"3681": {"is_small": true}, |
||||||
|
"3682": {"is_small": true}, |
||||||
|
"3691": {"is_small": true}, |
||||||
|
"3692": {"is_small": true}, |
||||||
|
"3959": {"is_small": true}, |
||||||
|
"11558": {"is_small": true}, |
||||||
|
"11559": {"is_small": true}, |
||||||
|
"3b5:10150": {"is_small": true}, |
||||||
|
"3b5:10151": {"is_small": true}, |
||||||
|
"11600": {"is_small": true}, |
||||||
|
"11604": {"is_small": true}, |
||||||
|
"3b5:7871": {"is_small": true} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
{ |
||||||
|
|
||||||
|
"1555": { |
||||||
|
"name": "2pdr Portee", |
||||||
|
"front_images": [ "br/vehicles/portee.gif", "br/vehicles/portee0.gif" ], |
||||||
|
"back_images": null |
||||||
|
}, |
||||||
|
|
||||||
|
"2212": { |
||||||
|
"name": "76* INF FRC", |
||||||
|
"front_images": [ "al/gun/alINF76.gif", "al/gun/alINF76u.gif" ], |
||||||
|
"back_images": "al/gun/alINF76b.gif" |
||||||
|
}, |
||||||
|
|
||||||
|
"7409": { |
||||||
|
"name": "76 ItK/28 B(s)", |
||||||
|
"front_images": "fi/gun/fiAA76L.png", |
||||||
|
"back_images": [ "fi/gun/fiAA76L.png", "fi/gun/fiAA76LB.png" ] |
||||||
|
}, |
||||||
|
|
||||||
|
"adf:1828": { |
||||||
|
"name": "105 ART wz.29", |
||||||
|
"front_images": "po/gun/poARTwz29-BFP.png", |
||||||
|
"back_images": [ "po/gun/poARTwz29-BFP.png", "po/gun/poARTwz29-BFPb.png" ] |
||||||
|
}, |
||||||
|
"adf:1829": { |
||||||
|
"name": "120* ART wz09.31", |
||||||
|
"front_images": "po/gun/poARTwz0931-BFP.png", |
||||||
|
"back_images": [ "po/gun/poARTwz0931-BFP.png", "po/gun/poARTwz0931-BFPb.png" ] |
||||||
|
}, |
||||||
|
"adf:1830": { |
||||||
|
"name": "155 ART wz.17", |
||||||
|
"front_images": "po/gun/poARTwz17-BFP.png", |
||||||
|
"back_images": [ "po/gun/poARTwz17-BFP.png", "po/gun/poARTwz17-BFPb.png" ] |
||||||
|
}, |
||||||
|
|
||||||
|
"3b5:3676": { |
||||||
|
"name": "M19A1 MGMC", |
||||||
|
"front_images": [ "us/veh/usM19A1MGMC(trailer)KFW.png", "us/veh/usM19A1MGMC(KFW).png" ], |
||||||
|
"back_images": null |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,2 @@ |
|||||||
|
{ |
||||||
|
} |
@ -0,0 +1,65 @@ |
|||||||
|
{ |
||||||
|
"6996": {"is_small": true}, |
||||||
|
"485": {"is_small": true}, |
||||||
|
"850": {"is_small": true}, |
||||||
|
"849": {"is_small": true}, |
||||||
|
"12689": {"is_small": true}, |
||||||
|
"856": {"is_small": true}, |
||||||
|
"857": {"is_small": true}, |
||||||
|
"11336": {"is_small": true}, |
||||||
|
"858": {"is_small": true}, |
||||||
|
"11337": {"is_small": true}, |
||||||
|
"1149": {"is_small": true}, |
||||||
|
"1153": {"is_small": true}, |
||||||
|
"12687": {"is_small": true}, |
||||||
|
"3b5:7613": {"is_small": true}, |
||||||
|
"11359": {"is_small": true}, |
||||||
|
"3b5:11259": {"is_small": true}, |
||||||
|
"1632": {"is_small": true}, |
||||||
|
"1636": {"is_small": true}, |
||||||
|
"1641": {"is_small": true}, |
||||||
|
"1648": {"is_small": true}, |
||||||
|
"1982": {"is_small": true}, |
||||||
|
"1983": {"is_small": true}, |
||||||
|
"1984": {"is_small": true}, |
||||||
|
"1985": {"is_small": true}, |
||||||
|
"1986": {"is_small": true}, |
||||||
|
"1987": {"is_small": true}, |
||||||
|
"1988": {"is_small": true}, |
||||||
|
"2172": {"is_small": true}, |
||||||
|
"2173": {"is_small": true}, |
||||||
|
"2176": {"is_small": true}, |
||||||
|
"2179": {"is_small": true}, |
||||||
|
"11391": {"is_small": true}, |
||||||
|
"11392": {"is_small": true}, |
||||||
|
"11395": {"is_small": true}, |
||||||
|
"11396": {"is_small": true}, |
||||||
|
"11440": {"is_small": true}, |
||||||
|
"3b5:8401": {"is_small": true}, |
||||||
|
"3b5:8402": {"is_small": true}, |
||||||
|
"2465": {"is_small": true}, |
||||||
|
"2474": {"is_small": true}, |
||||||
|
"3252": {"is_small": true}, |
||||||
|
"3253": {"is_small": true}, |
||||||
|
"3263": {"is_small": true}, |
||||||
|
"3422": {"is_small": true}, |
||||||
|
"3428": {"is_small": true}, |
||||||
|
"6730": {"is_small": true}, |
||||||
|
"3605": {"is_small": true}, |
||||||
|
"3608": {"is_small": true}, |
||||||
|
"6763": {"is_small": true}, |
||||||
|
"3679": {"is_small": true}, |
||||||
|
"3680": {"is_small": true}, |
||||||
|
"3681": {"is_small": true}, |
||||||
|
"3682": {"is_small": true}, |
||||||
|
"3691": {"is_small": true}, |
||||||
|
"3692": {"is_small": true}, |
||||||
|
"3959": {"is_small": true}, |
||||||
|
"11558": {"is_small": true}, |
||||||
|
"11559": {"is_small": true}, |
||||||
|
"3b5:10150": {"is_small": true}, |
||||||
|
"3b5:10151": {"is_small": true}, |
||||||
|
"11600": {"is_small": true}, |
||||||
|
"11604": {"is_small": true}, |
||||||
|
"3b5:7871": {"is_small": true} |
||||||
|
} |
@ -0,0 +1,147 @@ |
|||||||
|
{ |
||||||
|
|
||||||
|
"2474": { |
||||||
|
"expected": { |
||||||
|
"name": "Goliath", |
||||||
|
"front_images": [ "ge/gegol.gif", "ge/gegolb.gif" ], |
||||||
|
"back_images": null |
||||||
|
}, |
||||||
|
"updated": { |
||||||
|
"front_images": "ge/gegol.gif" |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
"1555": { |
||||||
|
"expected": { |
||||||
|
"name": "2pdr Portee", |
||||||
|
"front_images": "br/vehicles/portee.gif", |
||||||
|
"back_images": [ "br/vehicles/portee.gif", "br/vehicles/portee0.gif" ] |
||||||
|
}, |
||||||
|
"updated": { |
||||||
|
"front_images": [ "br/vehicles/portee.gif", "br/vehicles/portee0.gif" ], |
||||||
|
"back_images": null |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
"3463": { |
||||||
|
"expected": { |
||||||
|
"name": "75L AA 75/46", |
||||||
|
"front_images": [ "it/gun/itAA7546.gif", "it/gun/itAA7546b.gif" ], |
||||||
|
"back_images": [ "it/gun/itAA7546b.gif", "it/gun/itAA7546lb.gif" ] |
||||||
|
}, |
||||||
|
"updated": { |
||||||
|
"front_images": "it/gun/itAA7546.gif", |
||||||
|
"back_images": "it/gun/itAA7546b.gif" |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
"3776": { |
||||||
|
"expected": { |
||||||
|
"name": "37* INF Skoda IG", |
||||||
|
"front_images": [ "ax/gun/buIN37s.gif", "ax/gun/buIN37s2.gif" ], |
||||||
|
"back_images": "ax/gun/buIN37sb.gif" |
||||||
|
}, |
||||||
|
"updated": { |
||||||
|
"front_images": "ax/gun/buIN37s.gif" |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
"3777": { |
||||||
|
"expected": { |
||||||
|
"name": "70* INF Skoda IG", |
||||||
|
"front_images": [ "ax/gun/buIN37s.gif", "ax/gun/buIN37s2.gif" ], |
||||||
|
"back_images": "ax/gun/buIN37sb.gif" |
||||||
|
}, |
||||||
|
"updated": { |
||||||
|
"front_images": "ax/gun/buIN37s2.gif" |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
"6802": { |
||||||
|
"expected": { |
||||||
|
"name": "20L (4) AA", |
||||||
|
"front_images": [ "fi/gun/fi20L4 _2.png", "fi/gun/fi20L4 _2 LIM.png" ], |
||||||
|
"back_images": null |
||||||
|
}, |
||||||
|
"updated": { |
||||||
|
"front_images": "fi/gun/fi20L4 _2.png" |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
"6803": { |
||||||
|
"expected": { |
||||||
|
"name": "20L VKT (12) AA", |
||||||
|
"front_images": [ "fi/gun/fi20L12.png", "fi/gun/fi20L12L.png" ], |
||||||
|
"back_images": null |
||||||
|
}, |
||||||
|
"updated": { |
||||||
|
"front_images": "fi/gun/fi20L12.png" |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
"6804": { |
||||||
|
"expected": { |
||||||
|
"name": "40L Bofors AA (s)", |
||||||
|
"front_images": [ "fi/gun/fi40L.png", "fi/gun/fi40LL.png" ], |
||||||
|
"back_images": null |
||||||
|
}, |
||||||
|
"updated": { |
||||||
|
"front_images": "fi/gun/fi40L.png" |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
"adf:1824": { |
||||||
|
"expected": { |
||||||
|
"name": "37L AT PTP obr. 30", |
||||||
|
"front_images": "ru/gun/ruAT37L.gif", |
||||||
|
"back_images": "ru/gun/ruAT37Lb.gif" |
||||||
|
}, |
||||||
|
"updated": { |
||||||
|
"front_images": "ru/gun/ru37LPTPobr30.png" |
||||||
|
} |
||||||
|
}, |
||||||
|
"adf:1822": { |
||||||
|
"expected": { |
||||||
|
"name": "37* INF PP obr. 15R", |
||||||
|
"front_images": "ru/gun/ruINF37s.gif", |
||||||
|
"back_images": "ru/gun/ruINF37sb.gif" |
||||||
|
}, |
||||||
|
"updated": { |
||||||
|
"front_images": "ru/gun/ru37PPobr15R.png" |
||||||
|
} |
||||||
|
}, |
||||||
|
"adf:1823": { |
||||||
|
"expected": { |
||||||
|
"name": "76* INF PP obr. 27", |
||||||
|
"front_images": "ru/gun/ruINF76s.gif", |
||||||
|
"back_images": "ru/gun/ruINF76sb.gif" |
||||||
|
}, |
||||||
|
"updated": { |
||||||
|
"front_images": "ru/gun/ru76PPobr27.png" |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
"3b5:10093": { |
||||||
|
"expected": { |
||||||
|
"name": "SL truck", |
||||||
|
"front_images": [ "sh/SL3b(KFW).png", "sh/SL4b(KFW).png", "sh/SL5b(KFW).png", "sh/SL6b(KFW).png", "sh/SL1b(KFW).png", "sh/SL2b(KFW).png" ], |
||||||
|
"back_images": [ "sh/SL3(KFW).png", "sh/SL4(KFW).png", "sh/SL5(KFW).png", "sh/SL6(KFW).png", "sh/SL1(KFW).png", "sh/SL2(KFW).png" ] |
||||||
|
}, |
||||||
|
"updated": { |
||||||
|
"front_images": "us/veh/usSearchlight(KFW).png", |
||||||
|
"back_images": null |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
"08d:75": { |
||||||
|
"expected": { |
||||||
|
"name": "RCL 75*", |
||||||
|
"front_images": "amrcl75-malf.png", |
||||||
|
"back_images": "dm-75rcl.gif" |
||||||
|
}, |
||||||
|
"updated": { |
||||||
|
"front_images": "amrcl75.png" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
{ |
||||||
|
|
||||||
|
"1555": { |
||||||
|
"name": "2pdr Portee", |
||||||
|
"front_images": [ "br/vehicles/portee.gif", "br/vehicles/portee0.gif" ], |
||||||
|
"back_images": null |
||||||
|
}, |
||||||
|
|
||||||
|
"2212": { |
||||||
|
"name": "76* INF FRC", |
||||||
|
"front_images": [ "al/gun/alINF76.gif", "al/gun/alINF76u.gif" ], |
||||||
|
"back_images": "al/gun/alINF76b.gif" |
||||||
|
}, |
||||||
|
|
||||||
|
"7409": { |
||||||
|
"name": "76 ItK/28 B(s)", |
||||||
|
"front_images": "fi/gun/fiAA76L.png", |
||||||
|
"back_images": [ "fi/gun/fiAA76L.png", "fi/gun/fiAA76LB.png" ] |
||||||
|
}, |
||||||
|
|
||||||
|
"adf:1828": { |
||||||
|
"name": "105 ART wz.29", |
||||||
|
"front_images": "po/gun/poARTwz29-BFP.png", |
||||||
|
"back_images": [ "po/gun/poARTwz29-BFP.png", "po/gun/poARTwz29-BFPb.png" ] |
||||||
|
}, |
||||||
|
"adf:1829": { |
||||||
|
"name": "120* ART wz09.31", |
||||||
|
"front_images": "po/gun/poARTwz0931-BFP.png", |
||||||
|
"back_images": [ "po/gun/poARTwz0931-BFP.png", "po/gun/poARTwz0931-BFPb.png" ] |
||||||
|
}, |
||||||
|
"adf:1830": { |
||||||
|
"name": "155 ART wz.17", |
||||||
|
"front_images": "po/gun/poARTwz17-BFP.png", |
||||||
|
"back_images": [ "po/gun/poARTwz17-BFP.png", "po/gun/poARTwz17-BFPb.png" ] |
||||||
|
}, |
||||||
|
|
||||||
|
"3b5:3676": { |
||||||
|
"name": "M19A1 MGMC", |
||||||
|
"front_images": [ "us/veh/usM19A1MGMC(trailer)KFW.png", "us/veh/usM19A1MGMC(KFW).png" ], |
||||||
|
"back_images": null |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,2 @@ |
|||||||
|
{ |
||||||
|
} |