Added snippets for National Capabilities.

master
Pacman Ghost 4 years ago
parent f746b95408
commit 61b04dfa16
  1. 3
      .pylintrc
  2. 4
      vasl_templates/main_window.py
  3. 1
      vasl_templates/webapp/__init__.py
  4. 55
      vasl_templates/webapp/data/default-template-pack/nat_caps.j2
  5. 311
      vasl_templates/webapp/data/default-template-pack/national-capabilities.json
  6. 18
      vasl_templates/webapp/nat_caps.py
  7. 5
      vasl_templates/webapp/snippets.py
  8. 3
      vasl_templates/webapp/static/css/tabs-scenario.css
  9. 2
      vasl_templates/webapp/static/css/tabs.css
  10. BIN
      vasl_templates/webapp/static/images/nat-caps.png
  11. BIN
      vasl_templates/webapp/static/images/oba-info.png
  12. 93
      vasl_templates/webapp/static/main.js
  13. 117
      vasl_templates/webapp/static/nat_caps.js
  14. 177
      vasl_templates/webapp/static/snippets.js
  15. 4
      vasl_templates/webapp/static/sortable.js
  16. 3
      vasl_templates/webapp/static/user_settings.js
  17. 40
      vasl_templates/webapp/static/utils.js
  18. 12
      vasl_templates/webapp/static/vassal.js
  19. 1
      vasl_templates/webapp/templates/index.html
  20. 70
      vasl_templates/webapp/templates/national-capabilities.html
  21. 9
      vasl_templates/webapp/templates/tabs-scenario.html
  22. 5
      vasl_templates/webapp/templates/user-settings-dialog.html
  23. 15
      vasl_templates/webapp/tests/fixtures/data/default-template-pack/nat_caps.j2
  24. 31
      vasl_templates/webapp/tests/fixtures/data/default-template-pack/national-capabilities.json
  25. 12
      vasl_templates/webapp/tests/fixtures/nat-caps/american/1940.txt
  26. 12
      vasl_templates/webapp/tests/fixtures/nat-caps/american/1941.txt
  27. 12
      vasl_templates/webapp/tests/fixtures/nat-caps/american/1942.txt
  28. 12
      vasl_templates/webapp/tests/fixtures/nat-caps/american/1943.txt
  29. 12
      vasl_templates/webapp/tests/fixtures/nat-caps/american/1944.txt
  30. 12
      vasl_templates/webapp/tests/fixtures/nat-caps/american/1945.txt
  31. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/anzac/1940.txt
  32. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/anzac/1941.txt
  33. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/anzac/1942.txt
  34. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/anzac/1943.txt
  35. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/anzac/1944.txt
  36. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/anzac/1945.txt
  37. 9
      vasl_templates/webapp/tests/fixtures/nat-caps/belgian/1940.txt
  38. 9
      vasl_templates/webapp/tests/fixtures/nat-caps/belgian/1941.txt
  39. 9
      vasl_templates/webapp/tests/fixtures/nat-caps/belgian/1942.txt
  40. 9
      vasl_templates/webapp/tests/fixtures/nat-caps/belgian/1943.txt
  41. 9
      vasl_templates/webapp/tests/fixtures/nat-caps/belgian/1944.txt
  42. 9
      vasl_templates/webapp/tests/fixtures/nat-caps/belgian/1945.txt
  43. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british/1940.txt
  44. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british/1941.txt
  45. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british/1942.txt
  46. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british/1943.txt
  47. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british/1944.txt
  48. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british/1945.txt
  49. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british~canadian/1940.txt
  50. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british~canadian/1941.txt
  51. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british~canadian/1942.txt
  52. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british~canadian/1943.txt
  53. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british~canadian/1944.txt
  54. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british~canadian/1945.txt
  55. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british~newzealand/1940.txt
  56. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british~newzealand/1941.txt
  57. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british~newzealand/1942.txt
  58. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british~newzealand/1943.txt
  59. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british~newzealand/1944.txt
  60. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/british~newzealand/1945.txt
  61. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/bulgarian/1940.txt
  62. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/bulgarian/1941.txt
  63. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/bulgarian/1942.txt
  64. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/bulgarian/1943.txt
  65. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/bulgarian/1944.txt
  66. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/bulgarian/1945.txt
  67. 11
      vasl_templates/webapp/tests/fixtures/nat-caps/burmese/1940.txt
  68. 11
      vasl_templates/webapp/tests/fixtures/nat-caps/burmese/1941.txt
  69. 11
      vasl_templates/webapp/tests/fixtures/nat-caps/burmese/1942.txt
  70. 11
      vasl_templates/webapp/tests/fixtures/nat-caps/burmese/1943.txt
  71. 11
      vasl_templates/webapp/tests/fixtures/nat-caps/burmese/1944.txt
  72. 11
      vasl_templates/webapp/tests/fixtures/nat-caps/burmese/1945.txt
  73. 11
      vasl_templates/webapp/tests/fixtures/nat-caps/chinese/1940.txt
  74. 11
      vasl_templates/webapp/tests/fixtures/nat-caps/chinese/1941.txt
  75. 11
      vasl_templates/webapp/tests/fixtures/nat-caps/chinese/1942.txt
  76. 11
      vasl_templates/webapp/tests/fixtures/nat-caps/chinese/1943.txt
  77. 11
      vasl_templates/webapp/tests/fixtures/nat-caps/chinese/1944.txt
  78. 11
      vasl_templates/webapp/tests/fixtures/nat-caps/chinese/1945.txt
  79. 15
      vasl_templates/webapp/tests/fixtures/nat-caps/chinese~gmd/1940.txt
  80. 15
      vasl_templates/webapp/tests/fixtures/nat-caps/chinese~gmd/1941.txt
  81. 15
      vasl_templates/webapp/tests/fixtures/nat-caps/chinese~gmd/1942.txt
  82. 15
      vasl_templates/webapp/tests/fixtures/nat-caps/chinese~gmd/1943.txt
  83. 15
      vasl_templates/webapp/tests/fixtures/nat-caps/chinese~gmd/1944.txt
  84. 15
      vasl_templates/webapp/tests/fixtures/nat-caps/chinese~gmd/1945.txt
  85. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/croatian/1940.txt
  86. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/croatian/1941.txt
  87. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/croatian/1942.txt
  88. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/croatian/1943.txt
  89. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/croatian/1944.txt
  90. 14
      vasl_templates/webapp/tests/fixtures/nat-caps/croatian/1945.txt
  91. 9
      vasl_templates/webapp/tests/fixtures/nat-caps/danish/1940.txt
  92. 9
      vasl_templates/webapp/tests/fixtures/nat-caps/danish/1941.txt
  93. 9
      vasl_templates/webapp/tests/fixtures/nat-caps/danish/1942.txt
  94. 9
      vasl_templates/webapp/tests/fixtures/nat-caps/danish/1943.txt
  95. 9
      vasl_templates/webapp/tests/fixtures/nat-caps/danish/1944.txt
  96. 9
      vasl_templates/webapp/tests/fixtures/nat-caps/danish/1945.txt
  97. 9
      vasl_templates/webapp/tests/fixtures/nat-caps/dutch/1940.txt
  98. 9
      vasl_templates/webapp/tests/fixtures/nat-caps/dutch/1941.txt
  99. 9
      vasl_templates/webapp/tests/fixtures/nat-caps/dutch/1942.txt
  100. 9
      vasl_templates/webapp/tests/fixtures/nat-caps/dutch/1943.txt
  101. Some files were not shown because too many files have changed in this diff Show More

@ -142,7 +142,8 @@ disable=print-statement,
too-few-public-methods,
too-many-lines,
duplicate-code, # can't get it to shut up about @pytest.mark.skipif's :-/
no-else-return
no-else-return,
len-as-condition
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option

@ -86,8 +86,8 @@ class MainWindow( QWidget ):
if val :
self.restoreGeometry( val )
else :
self.resize( 1000, 600 )
self.setMinimumSize( 1000, 520 )
self.resize( 1050, 650 )
self.setMinimumSize( 1000, 595 )
# initialize the layout
layout = QVBoxLayout( self )

@ -97,6 +97,7 @@ import vasl_templates.webapp.snippets #pylint: disable=cyclic-import
import vasl_templates.webapp.files #pylint: disable=cyclic-import
import vasl_templates.webapp.vassal #pylint: disable=cyclic-import
import vasl_templates.webapp.vo_notes #pylint: disable=cyclic-import
import vasl_templates.webapp.nat_caps #pylint: disable=cyclic-import
import vasl_templates.webapp.roar #pylint: disable=cyclic-import
if app.config.get( "ENABLE_REMOTE_TEST_CONTROL" ):
print( "*** WARNING: Remote test control enabled! ***" )

@ -0,0 +1,55 @@
<html> <!-- vasl-templates:id {{SNIPPET_ID}} -->
<head>
<meta charset="utf-8">
<style>
{{CSS:common}}
td { padding: 2px 5px ; }
li.comment { font-size: 96% ; font-style: italic ; color: #404040 ; }
span.comment { font-size: 85% ; font-style: italic ; color: #404040 ; }
.exc { color: #404040 ; }
</style>
</head>
<table>
<tr> <td style="
background: {{OB_COLOR}} ;
border-bottom: 1px solid {{OB_COLOR_2}} ;
font-size: 105% ; font-weight: bold ;
">
<nobr>{{INCLUDE:player_flag}}{{PLAYER_NAME|nbsp}}&nbsp;Capabilities</nobr>
<tr> <td>
{%if NAT_CAPS%}
<ul>
{%if NAT_CAPS.GRENADES%} <li class="grenades"> {{NAT_CAPS.GRENADES}} {%endif%}
{%if NAT_CAPS.HOB_DRM%} <li class="hob-drm"> Heat of Battle: {{NAT_CAPS.HOB_DRM}} {%endif%}
{%if NAT_CAPS.TH_COLOR%} <li class="th-color"> {{NAT_CAPS.TH_COLOR}} {%endif%}
{%if NAT_CAPS.OBA_BLACK%}
<li> OBA: <span class="oba-black">{{NAT_CAPS.OBA_BLACK}}</span> <span class="oba-red">{{NAT_CAPS.OBA_RED}}</span>
{%if NAT_CAPS.OBA_ACCESS%} <span class="oba-access">(access: {{NAT_CAPS.OBA_ACCESS}})</span> {%endif%}
</span>
{%if NAT_CAPS.OBA_COMMENTS%}
<ul class="oba-comments"> {%for cmt in NAT_CAPS.OBA_COMMENTS%} <li class="comment"> {{cmt}} {%endfor%} </ul>
{%endif%}
{%endif%}
</ul>
{%if NAT_CAPS.NOTES%}
<ul class="notes" style="margin-top:5px;"> {%for note in NAT_CAPS.NOTES%}
<li> {{note}}
{%endfor%} </ul>
{%endif%}
{%else%}
Not available.
{%endif%}
</table>
</html>

@ -0,0 +1,311 @@
{
"german": {
"th_color": "Black",
"oba": [ "8B", "3R" ], "oba_access": "&le; 2",
"hob_drm": "0 DRM",
"grenades": "Smoke",
"notes": [
"{? 10/1943- | Inherent PF | No Inherent PF | Inherent PF (10/43+) ?}",
"{? 01/1944- | Inherent ATMM | No Inherent ATMM | Inherent ATMM (44+) ?}",
"SS: Disrupt &amp; RtPh Surrender NA vs Russians",
"Massacre OK",
"{? 01/1944- | Squad Assault Fire | No Squad Assault Fire | Squad Assault Fire (44+) ?}"
]
},
"russian": {
"th_color": "Red",
"oba": [ "5B", "2R" ], "oba_access": "&le; 1",
"hob_drm": "+2 DRM",
"grenades": null,
"notes": [
"Massacre OK",
"Deploy NA",
"Entrench -1 DRM",
"{? 11/1942- | Commissars NA | Commissars | Commissars (pre-11/42) ?}",
"Human Wave",
"{? 01/1942- | Riders OK | Riders NA | Riders (42+) ?}"
]
},
"american": {
"th_color": "{? 01/1944- | Black | Red | Black (44+) ?}",
"oba": [ "10B", "3R", "Plentiful Ammo included" ],
"oba_access": "&le; 2",
"hob_drm": "0 DRM",
"grenades": "SMOKE",
"notes": [
"U.S.M.C.: <ul> <li> Disruption NA <li> 7-6-8 can Self-Deploy <li> Vehicle [EXC: LC] Crew: Army 1-2-6 </ul>"
]
},
"kfw-american": {
"th_color": "{! 06/1950-08/1950 = Red | 09/1950- = Black | ??? !}",
"oba": [ "{! 06/1950-08/1950 = 9B | 09/1950- = 10B | ??? !}", "3R",
"{! 09/1950- = Plentiful Ammo included !}"
],
"oba_access": "&le; 2",
"hob_drm": [ "0 DRM", "+3 for Katusa; NA for TACP" ],
"grenades": "SMOKE",
"notes": [
"Rangers: 6-6-8 <ul> <li> Self-Rally OK <li> Self-Deploy (1TC) &amp; Self-Recombine OK <li> Cowering NA <li> Commandos <li> No Non-Qualified Use penalty for RCL <li> No Captured Use penalty for Communist SW </ul>",
"Airborne: 6-6-7",
"{! 06/1950-08/1950 = Early KW U.S. Army rules: <ul> <li> Always Lax <li> Ammo Shortage <li> SW repair only on \"1\" <li> Radio/Phone Contact reduced by 1 <li> AFV Inherent Crews have Morale 7 <li> All motorized vehicles have Red MP </ul> !}",
"Katusa: As U.S. Army MMC <ul> <li> HoB +3 DRM <li> Leader Creation +1 drm {! 09/1950-10/1951 = <li> ELR 2 <li> Allied Troop penalties with U.S. leaders !} </ul>",
"Disruption NA",
"7-6-8 can Self-Deploy",
"Use 5-5-8 when: <ul> <li> U.S.M.C. ELR Replacement is in effect <li> U.S.M.C. MMC re-arms </ul>",
"Tactical Air Control Party: <ul> <li> Inherent Radio (Contact = 9) <li> May set up HIP </ul>"
]
},
"british": {
"th_color": "Black",
"oba": [ "8B", "2R" ], "oba_access": "&le; 2",
"hob_drm": "-1 DRM",
"grenades": "{? 01/1944- | SMOKE | Smoke | SMOKE (44+) ?}",
"notes": [
"Elite &amp; 1st Line: Cowering NA",
"ANZAC: Stealthy (unless Green)",
"Gurkha: <ul> <li> -1 CC DRM <li> Disrupt &amp; RtPh Surrender NA <li> Commando (unless Green) <li> Stealthy </ul>"
]
},
"french": {
"th_color": [ "Black", "AFV use Red TH#" ],
"oba": [ "6B", "2R" ], "oba_access": "&le; 1",
"hob_drm": "+1 DRM",
"grenades": "Smoke",
"notes": []
},
"italian": {
"th_color": "Red",
"oba": [ "7B", "3R" ], "oba_access": "&le; 1",
"hob_drm": "+3 DRM",
"grenades": "Smoke",
"notes": [
"Escape NA",
"1st Line &amp; Conscript: <ul> <li> Surrender on HoB Final DR &ge; 10 <li> Deploy NA <li> +1 CC Capture DRM NA <li> Always Lax <li> 1 PAATC </ul>"
]
},
"finnish": {
"th_color": "Red",
"oba": [
"{! 01/1939-12/1940 = 6B | 01/1941-12/1942 = 7B | 01/1943-09/1944 = 8B | 10/1944- = 7B | ??? !}",
"3R",
"Plentiful Ammo included"
],
"oba_access": "&le; 1",
"hob_drm": "-1 DRM",
"grenades": null,
"notes": [
"Deploy (1TC) &amp; Recombine without Leader",
"Self-Rally OK [EXC: Conscript]",
"Cowering NA [EXC: Conscript]",
"Elite &amp; 1st Line: <ul> <li> Always Stealthy <li> Use FT/DC as Elite {? 07/1944- | <li> Inherent PF: <ul> <li> Range = 1 <li> PF Check &le; 2 <li> Max. shots = 1&frac12; &times; # Elite/1st Line squad-equivalents (FRD) </ul> | | <li> Inherent PF (7/44+) ?} </ul>",
"Ski-trained (don Skis = one MF)",
"Leader Creation NA",
"Captured Use penalties NA for Russian MG [EXC: LMG in 1939; .50-cal]"
]
},
"axis-minor": {
"th_color": "Red",
"oba": [ "6B", "3R" ], "oba_access": "&le; 1",
"hob_drm": "+3 DRM",
"grenades": "Smoke",
"notes": [
"Escape NA",
"1st Line &amp; Conscript: <ul> <li> 1 PAATC <li> Surrender on HoB Final DR &ge; 10 </ul>",
"Inherent PF in non-Crew MMC (Romanian 3/44+; Hungarian 6/44+): <ul> <li> Range = {? 06/1944- | 2 | 1 | 1 (pre-6/44), 2 thereafter ?} </ul>",
"{? 07/1943- | Inherent ATMM in Romanian non-Crew Elite &amp; 1st Line MMC (-2 CC DRM) | No Inherent ATMM | Inherent ATMM (7/43+) ?}"
]
},
"allied-minor": {
"th_color": "Red",
"oba": [ "6B", "3R" ], "oba_access": "&le; 1",
"hob_drm": "+2 DRM",
"grenades": "Smoke",
"notes": [
"+1 Broken Morale vs Italians",
"1st Line &amp; Green: 1 PAATC"
]
},
"japanese": {
"th_color": "Black",
"oba": [ "5B", "2R" ], "oba_access": "&le; 1",
"hob_drm": "+4 DRM",
"grenades": "SMOKE",
"notes": [
"SMC PTC/Pin/Break NA",
"Leaders: <ul> <li> Replacement NA <li> Casualty MC &rarr; elimination <li> Morale/Rally/Berserk as Commissar </ul>",
"Tank-Hunter Heroes &amp; ATMM",
"Banzai Charge (always Lax)",
"Elite &amp; 1st Line: Always Stealthy",
"Conscript: Always Lax",
"ATR/MMG/HMG Breakdown penalty",
"Always NA: <ul> <li> PAATC <li> Escape <li> RtPh Surrender <li> Disruption <li> Encircled lower Morale <li> Leader Creation </ul>",
"LLMC &rarr; LLTC if unbroken",
"Massacre OK",
"-1 Interrogation DRM",
"-2 Concealment drm",
"Enemy +2 search drm",
"Hand-to-Hand CC &amp; Hara-Kiri"
]
},
"chinese~gmd": {
"th_color": "Red",
"oba": [ "5B", "2R",
"6B/2R if Majority Squad Type is 5-3-7",
"5B/3R if Majority Squad Type is 3-3-7 or 3-3-6"
],
"oba_access": "&le; 1",
"hob_drm": "0 DRM",
"grenades": "SMOKE",
"notes": [
"Deploy NA",
"Lax at Night",
"+1 Leader Creation drm",
"1st Line &amp; Conscript: 1 PAATC",
"Human Wave",
"Dare-Death Squads [EXC: 5-3-7]"
]
},
"chinese": {
"th_color": "Red",
"oba": null,
"hob_drm": "+1 DRM",
"grenades": null,
"notes": [
"Cowering NA",
"Commissars",
"Human Wave",
"Dare-Death Squads"
]
},
"kfw-rok": {
"th_color": "{! -08/1950 = Red | 09/1950-04/1951 = Red (ROK) ; Black (KMC) | 05/1951- = Black | ??? !}",
"oba": [ "{! 06/1950- = 10B | ??? !}", "3R",
"{! 09/1950- = Plentiful Ammo included !}",
"{! 06/1950-08/1950 = ROK: 6B/3R !}"
],
"oba_access": "&le; 1 (ROK) ; 2 (KMC)",
"hob_drm": "+3/+4 DRM",
"grenades": "SMOKE",
"notes": [
"Republic of Korea (ROK): <ul> {! 06/1946-04/1951 = <li> Early KW ROK rules !} <li> 1st Line MMC Battle-Harden to Fanatic <li> 2nd Line &amp; Conscript MMC: <ul> <li> Always Lax <li> Deploy NA </ul> {? -10/1950 | <li> Human Bullets | | <li> Human Bullets (pre-11/50) ?} </ul>",
"Korean Marine Corps (KMC): <ul> {! 04/1949-07/1950 = <li> Japanese-Armed KMC | 08/1950- = <li> U.S.-Armed KMC !} {? -01/1951 | <li> SW B#/X#/ROF penalty | | <li> SW B#/X#/ROF penalty (pre-2/51) ?} </ul>"
]
},
"kfw-bcfk": {
"th_color": "Black",
"oba": [ "8B", "2R" ], "oba_access": "&le; 2",
"hob_drm": "-1 DRM",
"grenades": "SMOKE",
"notes": [
"2nd Line MMC: ELR Replacement &rarr; Disrupt",
"{? 01/1952- | Canadian squads have Assault Fire | | Canadian squads have Assault Fire (1/52+) ?}",
"Royal Marines: <ul> <li> Commandos <li> No Non-Qualified Use penalty for RCL <li> No Captured Use penalty for Communist SW <li> Self-Deploy (1TC) &amp; Self-Recombine OK </ul>"
]
},
"kfw-ounc": {
"th_color": "Black",
"oba": [ "9B", "3R" ], "oba_access": "&le; 1",
"hob_drm": [ "0 DRM", "+3 for Turkish" ],
"grenades": "SMOKE",
"notes": [
"2nd Line MMC: ELR Replacement &rarr; Disrupt [EXC: Turkish]",
"Bayonet Charge NTC NA for Ethiopian, French, Turkish leaders"
]
},
"kfw-kpa": {
"th_color": "Red",
"oba": [ "5B", "2R" ], "oba_access": "&le; 1",
"hob_drm": "+2 DRM",
"grenades": null,
"notes": [
"As Russian <ul> <li> Elite Personnel always Stealthy <li> Elite Squads may Deploy <li> Commissars <li> Massacre OK <li> Human Wave by SSR only </ul>",
"Suicide Heroes",
"Starshell restrictions",
"Assault Engineers: WP grenades",
"Communist Partisans: <ul> <li> Neither Elite nor Conscript/Green <li> Always Stealthy <li> Massacre OK <li> Disrupt &amp; RtPh Surrender NA </ul>"
]
},
"kfw-cpva": {
"th_color": "Red",
"oba": [
"{? 04/1951- | 7B | | 7B (4/51+) ?}",
"{! 04/1951-09/1952 = 3R | 10/1952- = 2R | ??? !}"
],
"oba_access": "&le; 1",
"hob_drm": "+1 DRM",
"grenades": null,
"notes": [
"Always Stealthy",
"Starshell restrictions",
"Armored Assault NA",
"Riders NA",
"Assault Engineers: WP grenades",
"{! 10/1950-03/1951 = Early KW CPVA rules !}",
"Leaders &amp; Political Officers increase Morale as if Commissar",
"SW B#/X#/ROF penalty",
"Restricted Fire",
"Infantry Platoon Movement",
"Hand-to-Hand CC (-1 DRM)",
"HS Infantry Overrun",
"Bugles",
"Entrench -1 DRM",
"PAATC NTC NA",
"Infantry Overrun NTC NA",
"Conceal if +2 Hindrance",
"Concealment -1 drm",
"Civilian Interrogation is always in effect"
]
},
"burmese": {
"th_color": "Red",
"oba": null,
"hob_drm": "+2 DRM",
"grenades": null,
"notes": [
"Dare-Death Squads (as if Chinese)",
"Elite and 1st Line MMC: Always Stealthy",
"Deploy NA [EXC: A20.5 &amp; A21.22]; Recombine OK",
"Leaders: Morale/Berserk/Rally as Commissar"
]
},
"indonesian": {
"th_color": "Red",
"oba": [ "5B", "3R" ],
"hob_drm": "+3 DRM",
"grenades": "Smoke",
"notes": [
"Tank-Hunter/DC Heroes (as if 1945 Japanese)",
"Hand-to-Hand Combat",
"Massacre OK",
"HoB DR &ge; 12 &rarr; Berserk",
"Deploy NA [EXC: A20.5 &amp; A21.22]; Recombine OK"
]
},
"thai": {
"th_color": "Black",
"oba": [ "7B", "3R" ],
"hob_drm": "0 DRM",
"grenades": "Smoke"
}
}

@ -0,0 +1,18 @@
""" Main webapp handlers. """
from flask import render_template
from vasl_templates.webapp import app
# ---------------------------------------------------------------------
@app.route( "/national-capabilities/<nat>/<theater>/<int:year>", defaults={"month":1} )
@app.route( "/national-capabilities/<nat>/<theater>/<int:year>/<int:month>" )
def get_national_capabilities( nat, theater, year, month ):
"""Get the national capabilities snippet."""
return render_template( "national-capabilities.html",
NATIONALITY = nat,
THEATER = theater,
YEAR = year,
MONTH = month
)

@ -44,9 +44,10 @@ def load_default_template_pack(): #pylint: disable=too-many-locals
"default-template-pack/"
)
data = { "templates": {} }
fname = os.path.join( base_dir, "nationalities.json" )
with open(fname,"r") as fp:
with open( os.path.join( base_dir, "nationalities.json" ), "r") as fp:
data["nationalities"] = json.load( fp )
with open( os.path.join( base_dir, "national-capabilities.json" ), "r" ) as fp:
data["national-capabilities"] = json.load( fp )
# NOTE: Similarly, we always load the default extras templates, and user-defined template packs
# can add to them, or modify existing ones, but not remove them.

@ -16,6 +16,9 @@
#panel-scenario label.header { font-weight: bold ; width: 3em ; text-align: center ; }
#panel-scenario input { margin-bottom: 0.25em ; }
#panel-scenario #oba-info { height: 1em ; }
.oba-info-tooltip { max-width: 500px ; }
#panel-scenario .select2-container { margin: 2px ; }
#panel-scenario .select2-selection__rendered { height: 23px ; line-height: 23px ; }
#panel-scenario .select2-selection__arrow { margin-top: -2px ; }

@ -19,7 +19,7 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#tabs-scenario { display: flex ; }
#tabs-scenario .left { width: 33.5em ; min-width: 33.5em ; }
#tabs-scenario .left { width: 32em ; min-width: 32em ; }
#tabs-scenario .right { flex-grow: 1 ; min-width: 25em ; }
#tabs-scenario .left { display: flex ; flex-direction: column ; }

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

@ -137,6 +137,12 @@ $(document).ready( function () {
onClose: on_scenario_date_change,
} ) ;
// initialize the OBA INFO tooltip
$( "#oba-info" ).tooltip( {
tooltipClass: "oba-info-tooltip",
content: make_oba_info_tooltip,
} ) ;
// initialize the SSR's
$("#ssr-sortable").sortable2( "init", {
add: add_ssr, edit: edit_ssr
@ -394,6 +400,8 @@ $(document).ready( function () {
template_id = "ob_vehicles" ;
else if ( template_id.substring(0,12) === "ob_ordnance_" )
template_id = "ob_ordnance" ;
else if ( template_id.substring(0,9) === "nat_caps_" )
template_id = "nat_caps" ;
$( "<a href='#' class='_edit-template-link_' data-id='" + template_id + "'" +
" onclick='edit_template(\"" + template_id + "\")'" +
"></a>"
@ -415,14 +423,16 @@ function init_snippet_button( $btn )
var template_id2 ;
if ( template_id.substring(0,9) === "ob_setup_" )
template_id2 = "ob_setup" ;
else if ( template_id.substring(0,21) == "ob_vehicles_ma_notes_" )
else if ( template_id.substring(0,21) === "ob_vehicles_ma_notes_" )
template_id2 = "ob_vehicles_ma_notes" ;
else if ( template_id.substring(0,21) == "ob_ordnance_ma_notes_" )
else if ( template_id.substring(0,21) === "ob_ordnance_ma_notes_" )
template_id2 = "ob_ordnance_ma_notes" ;
else if ( template_id.substring(0,12) == "ob_vehicles_" )
else if ( template_id.substring(0,12) === "ob_vehicles_" )
template_id2 = "ob_vehicles" ;
else if ( template_id.substring(0,12) == "ob_ordnance_" )
else if ( template_id.substring(0,12) === "ob_ordnance_" )
template_id2 = "ob_ordnance" ;
else if ( template_id.substring(0,9) === "nat_caps_" )
template_id2 = "nat_caps" ;
else
template_id2 = template_id ;
@ -435,12 +445,18 @@ function init_snippet_button( $btn )
"</div>"
] ;
var $newBtn = $( buf.join("") ) ;
$newBtn.find( "button" ).prepend(
$( "<img src='" + gImagesBaseUrl + "/snippet.png'>" )
).click( function( evt ) {
generate_snippet( $(this), evt, null ) ;
return false ;
} ).attr( "title", GENERATE_SNIPPET_HINT ) ;
var fname="snippet.png", style="" ;
if ( template_id.substring( 0, 9 ) === "nat_caps_" ) {
fname = "nat-caps.png" ;
style = "height:15px;margin-right:0;" ;
}
$newBtn.find( "button" )
.prepend( $( "<img src='" + gImagesBaseUrl + "/" + fname + "' style='" + style + "'>" ) )
.click( function( evt ) {
generate_snippet( $(this), evt, null ) ;
return false ;
} )
.attr( "title", GENERATE_SNIPPET_HINT ) ;
// add in the droplist
$newBtn.controlgroup() ;
@ -514,6 +530,10 @@ function update_page_load_status( id )
$("#tabs").tabs({ disabled: [] }) ;
$("#loader").fadeOut( 500 ) ;
adjust_footer_vspacers() ;
// position the PLAYERS snippet button
var $btn = $( ".snippet-control[data-id='players']" ) ;
var $sel = $( ".select2[name='PLAYER_2_SAN']" ) ;
$btn.offset( { left: $sel.offset().left + $sel.outerWidth() - $btn.outerWidth() } ) ;
// NOTE: The watermark image appears briefly in IE when reloading the page, but not even
// creating the watermark dynamically and removing it when the page unloads fixes it :-(
$("#watermark").fadeIn( 5*1000 ) ;
@ -717,6 +737,49 @@ function on_player_change( player_no )
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function make_oba_info_tooltip()
{
// initialize
var buf = [ "<table>" ] ;
buf.push( "<tr>", "<th colspan='2' style='font-size:105%;text-align:center;padding:5px;background:#e0e0e0;'> Off-Board Artillery" ) ;
// initialize
var params = {
SCENARIO_THEATER: $( "select.param[name='SCENARIO_THEATER']" ).val()
} ;
var scenario_date = get_scenario_date() ;
if ( scenario_date ) {
params.SCENARIO_MONTH = 1 + scenario_date.getMonth() ;
params.SCENARIO_YEAR = scenario_date.getFullYear() ;
}
// add the OBA info for each player
for ( var player_no=1 ; player_no <= 2 ; ++player_no ) {
buf.push( "<tr>" ) ;
var player_nat = $( "select[name='PLAYER_" + player_no + "']" ).val() ;
var display_name = get_nationality_display_name( player_nat ) ;
buf.push( "<td style='font-weight:bold;padding-right:0.5em;white-space:nowrap;'>", display_name+":" ) ;
set_nat_caps_params( player_nat, params ) ;
if ( ! params.NAT_CAPS )
params.NAT_CAPS = { OBA_BLACK: "-", OBA_RED: "-" } ;
buf.push( "<td>" ) ;
var colors = [ "BLACK", "RED" ] ;
for ( var i=0 ; i < colors.length ; ++i ) {
var val = params.NAT_CAPS[ "OBA_"+colors[i] ] || "-" ;
buf.push( "<span style='display:inline-block;width:2em;'>", val, "</span>" ) ;
}
if ( params.NAT_CAPS.OBA_COMMENTS ) {
for ( i=0 ; i < params.NAT_CAPS.OBA_COMMENTS.length ; ++i )
buf.push( "<tr>", "<td>", "<td style='font-size:90%;font-style:italic;color:#404040;'>", params.NAT_CAPS.OBA_COMMENTS[i] ) ;
}
}
buf.push( "</table>" ) ;
return buf.join( "" ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function update_ob_tab_header( player_no )
{
// update the OB tab header for the specified player
@ -741,6 +804,7 @@ function update_nationality_specific_buttons( player_no )
var theater = $( "select.param[name='SCENARIO_THEATER']" ).val().toLowerCase() ;
// hide/show each nationality-specific button
var $elem ;
for ( var button_id in NATIONALITY_SPECIFIC_BUTTONS ) {
var show = false ;
for ( var i=0 ; i < NATIONALITY_SPECIFIC_BUTTONS[button_id].length ; ++i ) {
@ -755,9 +819,16 @@ function update_nationality_specific_buttons( player_no )
show = nat.substr(0,pos) == player_nat && nat.substr(pos+1) !== theater ;
}
}
var $elem = $( "#panel-ob_notes_" + player_no + " div.snippet-control[data-id='" + button_id + "']" ) ;
$elem = $( "#panel-ob_notes_" + player_no + " div.snippet-control[data-id='" + button_id + "']" ) ;
$elem.css( "display", show ? "inline-block" : "none" ) ;
}
// update the CAPABILITIES button
var $btn = $( "button.generate[data-id='nat_caps_" + player_no + "']" ) ;
if ( get_national_capabilities( player_nat ) )
$btn.removeClass( "inactive" ) ;
else
$btn.addClass( "inactive" ) ;
}
// --------------------------------------------------------------------

@ -0,0 +1,117 @@
// --------------------------------------------------------------------
function set_nat_caps_params( player_nat, params )
{
// get the national capabilities
var is_kfw = params.SCENARIO_THEATER == "Korea" ;
var nat_caps = get_national_capabilities( player_nat, is_kfw ) ;
if ( ! nat_caps )
return ;
// initialize
params.NAT_CAPS = {} ;
var excRegex = new RegExp( /\[EXC: .*?\]/g ) ;
var val ;
function add_nat_cap( key, val ) {
if ( val !== undefined )
params.NAT_CAPS[ key ] = val ;
}
function fixup_content( val ) {
val = strReplaceAll( val, "1st", "1<sup>st</sup>" ) ;
val = strReplaceAll( val, "2nd", "2<sup>nd</sup>" ) ;
return wrapSubstrings( val, excRegex, "<span class='exc'>", "</span>" ) ;
}
// set the TH# color
if ( nat_caps.th_color ) {
if ( $.isArray( nat_caps.th_color ) ) {
add_nat_cap( "TH_COLOR",
make_time_based_comment( nat_caps.th_color[0], params.SCENARIO_MONTH, params.SCENARIO_YEAR ) + " TH#" +
" <span class='comment'>(" + nat_caps.th_color[1] + ")</span>"
) ;
} else {
var th_color = make_time_based_comment( nat_caps.th_color, params.SCENARIO_MONTH, params.SCENARIO_YEAR ) ;
var match = th_color.match( /\(.+\)$/ ) ;
if ( match )
th_color = th_color.substring(0,match.index) + "TH# " + match[0] ;
else
th_color += " TH#" ;
add_nat_cap( "TH_COLOR", th_color ) ;
}
}
// set the HoB DRM
if ( nat_caps.hob_drm ) {
if ( $.isArray( nat_caps.hob_drm ) ) {
add_nat_cap( "HOB_DRM",
nat_caps.hob_drm[0] +
" <span class='comment'>(" + nat_caps.hob_drm[1] + ")</span>"
) ;
} else {
add_nat_cap( "HOB_DRM", nat_caps.hob_drm ) ;
}
}
// set the type of grenades available
if ( nat_caps.grenades !== undefined ) {
val = (nat_caps.grenades === null) ? "No" : make_time_based_comment( nat_caps.grenades, params.SCENARIO_MONTH, params.SCENARIO_YEAR ) ;
add_nat_cap( "GRENADES", val+" grenades" ) ;
}
// set the OBA red/black numbers
if ( nat_caps.oba ) {
params.NAT_CAPS.OBA_BLACK = make_time_based_comment( nat_caps.oba[0], params.SCENARIO_MONTH, params.SCENARIO_YEAR ) ;
params.NAT_CAPS.OBA_RED = make_time_based_comment( nat_caps.oba[1], params.SCENARIO_MONTH, params.SCENARIO_YEAR ) ;
if ( nat_caps.oba.length > 2 ) {
var oba_comments = [] ;
for ( i=2 ; i < nat_caps.oba.length ; ++i ) {
val = make_time_based_comment( nat_caps.oba[i], params.SCENARIO_MONTH, params.SCENARIO_YEAR ) ;
if ( val )
oba_comments.push( val ) ;
}
if ( oba_comments.length > 0 )
params.NAT_CAPS.OBA_COMMENTS = oba_comments ;
}
}
// set the OBA access number
add_nat_cap( "OBA_ACCESS", nat_caps.oba_access ) ;
// add any additional notes
if ( nat_caps.notes ) {
params.NAT_CAPS.NOTES = [] ;
for ( i=0 ; i < nat_caps.notes.length ; ++i ) {
val = make_time_based_comment( nat_caps.notes[i], params.SCENARIO_MONTH, params.SCENARIO_YEAR ) ;
if ( val )
params.NAT_CAPS.NOTES.push( fixup_content( val ) ) ;
}
}
}
// --------------------------------------------------------------------
function get_national_capabilities( nat, is_kfw )
{
// get the capabilities for the specified nationality
if ( ! nat )
return null ;
if ( is_kfw ) {
if ( nat === "american" )
nat = "kfw-american" ;
else if ( ["british","british~canadian","british~newzealand"].indexOf( nat ) !== -1 )
nat = "kfw-bcfk" ;
}
else if ( nat === "anzac" || nat === "free-french" || nat.substring(0,8) === "british~" )
nat = "british" ;
var nat_caps = gTemplatePack["national-capabilities"][ nat ] ;
if ( nat_caps )
return nat_caps ;
if ( gTemplatePack.nationalities[ nat ] ) {
var nat_type = gTemplatePack.nationalities[ nat ].type ;
if ( nat_type )
return gTemplatePack["national-capabilities"][ nat_type ] ;
}
return null ;
}

@ -151,7 +151,11 @@ function make_snippet( $btn, params, extra_params, show_date_warnings )
params.PLAYER_FLAG_SIZE = "width='11' height='11'" ;
// set player-specific parameters
var player_no = get_player_no_for_element( $btn ) ;
var player_no ;
if ( template_id.substring( 0, 9 ) === "nat_caps_" )
player_no = template_id.substring( 9 ) ;
else
player_no = get_player_no_for_element( $btn ) ;
var player_nat = get_player_nat( player_no ) ;
if ( player_no ) {
params.PLAYER_NAME = get_nationality_display_name( params["PLAYER_"+player_no] ) ;
@ -213,6 +217,8 @@ function make_snippet( $btn, params, extra_params, show_date_warnings )
params.OB_VO_WIDTH = params.OB_ORDNANCE_WIDTH_2 ;
snippet_save_name = params.PLAYER_2 + " ordnance" ;
}
if ( template_id === "nat_caps_1" || template_id === "nat_caps_2" )
template_id = "nat_caps" ;
// adjust comments
adjust_vo_comments( params ) ;
@ -242,12 +248,12 @@ function make_snippet( $btn, params, extra_params, show_date_warnings )
set_vo_note( "ordnance" ) ;
// generate snippets for multi-applicable vehicle/ordnance notes
var pos ;
var pos, i ;
function add_ma_notes( ma_notes, keys, param_name, nat, vo_type ) {
if ( ! keys )
return ;
params[ param_name ] = [] ;
for ( var i=0 ; i < keys.length ; ++i ) {
for ( i=0 ; i < keys.length ; ++i ) {
var ma_note = get_ma_note( nat, vo_type, keys[i] ) ;
var key = keys[i] ;
var extn_marker = "" ;
@ -301,7 +307,7 @@ function make_snippet( $btn, params, extra_params, show_date_warnings )
template_id = "ob_" + vo_type + "_ma_notes" ;
var vo_type_uc = vo_type.toUpperCase() ;
var postfixes = [ "MA_NOTES", "MA_NOTES_WIDTH", "EXTRA_MA_NOTES", "EXTRA_MA_NOTES_CAPTION" ] ;
for ( var i=0 ; i < postfixes.length ; ++i ) {
for ( i=0 ; i < postfixes.length ; ++i ) {
params[ "OB_" + postfixes[i] ] = params[ "OB_" + vo_type_uc + "_" + postfixes[i] + "_" + player_no ] ;
}
snippet_save_name = params["PLAYER_"+player_no] + (vo_type === "vehicles" ? " vehicle notes" : " ordnance notes") ;
@ -371,6 +377,9 @@ function make_snippet( $btn, params, extra_params, show_date_warnings )
params.BAZ_RANGE = 4 ;
}
// set the national capabilities parameters
set_nat_caps_params( player_nat, params ) ;
// check for mandatory parameters
if ( template_id in _MANDATORY_PARAMS ) {
var missing_params = [] ;
@ -432,7 +441,7 @@ function make_snippet( $btn, params, extra_params, show_date_warnings )
snippet = func( params, {
autoEscape: false,
filters: {
join: function( vals, sep ) { return vals.join( sep ) ; },
join: function( vals, sep ) { return vals ? vals.join(sep) : "" ; },
nbsp: function( val ) { return strReplaceAll( val, " ", "&nbsp;" ) ; },
} ,
} ) ;
@ -484,20 +493,14 @@ function adjust_vo_comments( params )
}
// allow comment EXC's to be styled
var excRegex = new RegExp( /\[EXC: .*?\]/ ) ;
var excRegex = new RegExp( /\[EXC: .*?\]/g ) ;
function adjustExc( val ) {
var match = val.match( excRegex ) ;
if ( match ) {
val = val.substring( 0, match.index ) +
"<span class='exc'>" + match[0] + "</span>" +
val.substring( match.index + match[0].length ) ;
}
return val ;
return wrapSubstrings( val, excRegex, "<span class='exc'>", "</span>" ) ;
}
// adjust comments
if ( params.OB_VO ) {
for ( var i=0 ; i < params.OB_VO.length ; ++i ) {
for ( i=0 ; i < params.OB_VO.length ; ++i ) {
if ( ! params.OB_VO[i].comments )
continue ;
for ( var j=0 ; j < params.OB_VO[i].comments.length ; ++j ) {
@ -935,40 +938,10 @@ function get_vo_comments( vo_entry, month, year )
if ( ! vo_entry.comments )
return vo_entry.comments ;
function parseDate( val ) {
if ( ! val )
return null ;
var match = val.trim().match( /^(\d\d)\/(19\d\d)$/ ) ;
if ( ! match )
return null ;
return [ match[1], match[2] ] ;
}
// generate the vehicle/ordnance's comments
var voComments=[], cmt, i ;
for ( i=0 ; i < vo_entry.comments.length ; ++i ) {
cmt = vo_entry.comments[i] ;
if ( cmt.substr(0,2) === "{?" && cmt.substr(cmt.length-2) === "?}" ) {
// this is a time-based comment, check the scenario date
var words = cmt.substring( 2, cmt.length-2 ).split( "|" ) ;
var dates = words[0].split( "-" ) ;
dates = [ parseDate(dates[0]), parseDate(dates[1]) ] ;
if ( words.length != 4 || dates.length != 2 || (!dates[0] && !dates[1]) ) {
showErrorMsg( "Invalid time-based vehicle/ordnance comment: " + cmt ) ;
continue ;
}
if ( !month || !year )
cmt = words[3] ;
else {
var rc = true ;
if ( dates[0] && ( year < dates[0][1] || ( year == dates[0][1] && month < dates[0][0] ) ) )
rc = false ;
if ( dates[1] && ( year > dates[1][1] || ( year == dates[1][1] && month > dates[1][0] ) ) )
rc = false ;
cmt = rc ? words[1] : words[2] ;
}
}
cmt = cmt.trim() ;
cmt = make_time_based_comment( vo_entry.comments[i], month, year ) ;
if ( cmt )
voComments.push( cmt ) ;
}
@ -996,6 +969,108 @@ function get_vo_comments( vo_entry, month, year )
return voComments ;
}
function make_time_based_comment( val, month, year )
{
function parseDateControl( val ) {
// parse a date control string
var dates = val.split( "-" ) ;
if ( dates.length != 2 )
return null ;
for ( var i=0 ; i < 2 ; ++i ) {
var date = dates[i].trim() ;
if ( date !== "" ) {
var match = date.match( /^(\d\d)\/(19\d\d)$/ ) ;
if ( ! match )
return null ;
dates[i] = [ match[1], match[2] ] ;
} else {
dates[i] = null ;
}
}
return dates ;
}
function checkDateControl( dateControl ) {
// check if the date passed in falls within the date control
if ( dateControl[0] && ( year < dateControl[0][1] || ( year == dateControl[0][1] && month < dateControl[0][0] ) ) )
return false ;
if ( dateControl[1] && ( year > dateControl[1][1] || ( year == dateControl[1][1] && month > dateControl[1][0] ) ) )
return false ;
return true ;
}
// process any time-based values
var words, dateControl ;
for ( ; ; ) {
// check for a time-based substitution
var parts = findDelimitedSubstring( val, "{?", "?}" ) ;
if ( $.isArray( parts ) ) {
// found one - this form has the following syntax:
// {? DATE CONTROL | within the date control | outside the date control | fallback text ?}
// parse the date control
words = parts[1].split( "|" ) ;
dateControl = parseDateControl( words[0] ) ;
if ( words.length != 4 || dateControl === null ) {
showErrorMsg( "Invalid time-based comment: " + val ) ;
return null ;
}
// figure out which value to use
if ( month && year )
val = parts[0] + words[ checkDateControl(dateControl) ? 1 : 2 ].trim() + parts[2] ;
else
val = parts[0] + words[3].trim() + parts[2] ;
continue ;
}
// check for a time-based substitution
parts = findDelimitedSubstring( val, "{!", "!}" ) ;
if ( $.isArray( parts ) ) {
// found one - this form has the following syntax:
// {! DATE CONTROL = text | DATE CONTROL = text | etc... | fallback text !}
var fallbackText = "" ;
choices = parts[1].split( "|" ) ;
for ( var i=0 ; i < choices.length ; ++i ) {
// parse the next choice
var pos = choices[i].indexOf( "=" ) ;
if ( pos !== -1 ) {
dateControl = parseDateControl( choices[i].substring( 0, pos ) ) ;
if ( dateControl !== null ) {
// the choice is valid - save it, and its substitution text
choices[i] = [ dateControl, choices[i].substring(pos+1).trim() ] ;
continue ;
}
}
// the choice is invalid
if ( i === choices.length-1 ) {
// this is the last choice - use it as the fallback text
fallbackText = choices.pop().trim() ;
break ;
} else {
showErrorMsg( "Invalid time-based comment: " + choices[i] ) ;
return null ;
}
}
// check each choice to try find a match
var replaceText = fallbackText ;
if ( month && year ) {
for ( i=0 ; i < choices.length ; ++i ) {
if ( checkDateControl( choices[i][0] ) ) {
// found a match - replace the content with the substitution text
replaceText = choices[i][1] ;
break ;
}
}
}
val = parts[0] + replaceText + parts[2] ;
}
// NOTE: If we get here, there are no more time-based substitutions to be made.
break ;
}
return val ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function make_capabilities( raw, vo_entry, vo_type, nat, elite, scenario_theater, scenario_year, scenario_month, show_warnings )
@ -1937,6 +2012,7 @@ function do_load_template_pack( fname, data )
var unknown_template_ids = [] ;
var template_pack = {
nationalities: $.extend( true, {}, gDefaultTemplatePack.nationalities ),
"national-capabilities": $.extend( true, {}, gDefaultTemplatePack["national-capabilities"] ),
templates: {},
css: {},
includes: {},
@ -1963,6 +2039,17 @@ function do_load_template_pack( fname, data )
$.extend( true, template_pack.nationalities, nationalities ) ;
return ;
}
if ( fname.toLowerCase() === "national-capabilities.json" ) {
var nat_caps = null ;
try {
nat_caps = JSON.parse( data ) ;
} catch( ex ) {
showWarningMsg( "Can't parse the nationalities JSON data:<div class='pre'>" + escapeHTML(ex) + "</div>" ) ;
return ;
}
$.extend( true, template_pack["national-capabilities"], nat_caps ) ;
return ;
}
var extn = getFilenameExtn( fname ) ;
if ( [".j2",".css",".include"].indexOf( extn ) === -1 ) {
invalid_filename_extns.push( fname ) ;

@ -77,7 +77,7 @@ $.fn.sortable2 = function( action, args )
$sortable2.data( "no_confirm_delete", args.no_confirm_delete ) ;
$sortable2.data( "on_edit", args.edit ) ;
var $add_btn = find_helper( $sortable2, "add" ) ;
$add_btn.prepend( $( "<div><img src='" + gImagesBaseUrl + "/sortable-add.png' class='sortable-add'> Add</div>" ) )
$add_btn.prepend( $( "<div style='white-space:nowrap;'><img src='" + gImagesBaseUrl + "/sortable-add.png' class='sortable-add'> Add</div>" ) )
.button( {} ) ;
var $add = find_helper( $sortable2, "add" ) ;
$add.prop( "title", "Add a new " + display_name[0] )
@ -85,7 +85,7 @@ $.fn.sortable2 = function( action, args )
if ( args.reset ) {
$sortable2.data( "on_reset", args.reset ) ;
var $reset_btn = find_helper( $sortable2, "reset" ) ;
$reset_btn.prepend( $( "<div><img src='" + gImagesBaseUrl + "/sortable-reset.png' class='sortable-reset'> Reset</div>" ) )
$reset_btn.prepend( $( "<div style='white-space:nowrap;'><img src='" + gImagesBaseUrl + "/sortable-reset.png' class='sortable-reset'> Reset</div>" ) )
.button( {} ) ;
var $reset = find_helper( $sortable2, "reset" ) ;
$reset.prop( "title", "Reset the " + display_name[1] )

@ -9,6 +9,7 @@ USER_SETTINGS = {
"date-format": "droplist",
"scenario-images-source": "droplist",
"hide-unavailable-ma-notes": "checkbox",
"auto-create-national-capabilities-labels": "checkbox",
"include-vasl-images-in-snippets": "checkbox",
"include-flags-in-snippets": "checkbox",
"custom-list-bullets": "checkbox",
@ -76,7 +77,7 @@ function user_settings()
dialogClass: "user-settings",
modal: true,
width: 460,
height: 320,
height: 340,
resizable: false,
create: function() {
init_dialog( $(this), "OK", true ) ;

@ -4,6 +4,8 @@
function get_nationality_display_name( nat_id )
{
// get the nationality's display name
if ( ! gTemplatePack.nationalities[ nat_id ] )
return null ;
return gTemplatePack.nationalities[ nat_id ].display_name ;
}
@ -85,6 +87,8 @@ function is_template_available( template_id )
// check if the specified template is available
if ( template_id.match( /^ob_(vehicles|ordnance).*_[12]$/ ) )
template_id = template_id.substring( 0, template_id.length-2 ) ;
else if ( template_id === "nat_caps_1" || template_id === "nat_caps_2" )
template_id = "nat_caps" ;
return gTemplatePack.templates[ template_id ] !== undefined ;
}
@ -426,6 +430,42 @@ function strReplaceAll( val, searchFor, replaceWith )
}
}
function findDelimitedSubstring( val, delim1, delim2 )
{
// search for a substring delimited by the 2 specified markers
if ( val === null || val === undefined )
return null ;
var pos = val.indexOf( delim1 ) ;
if ( pos === -1 )
return val ;
var pos2 = val.indexOf( delim2, pos ) ;
if ( pos2 === -1 )
return val ;
// found it - return the prefix/middle/postfix parts
return [
val.substring( 0, pos ),
val.substring( pos+delim1.length, pos2 ),
val.substring( pos2+delim2.length )
] ;
}
function wrapSubstrings( val, searchFor, delim1, delim2 )
{
// search for a substring and wrap it with the specified delimeters
if ( val === null || val === undefined )
return null ;
// FUDGE! matchAll() isn't available in the PyQt embedded browser :-/
var matches = [] ;
while ( ( match = searchFor.exec( val ) ) !== null )
matches.push( match ) ;
for ( var i=matches.length-1 ; i >= 0 ; --i ) {
val = val.substring( 0, matches[i].index ) +
delim1 + matches[i][0] + delim2 +
val.substring( matches[i].index + matches[i][0].length ) ;
}
return val ;
}
function getFilenameExtn( fname )
{
// get the filename extension

@ -100,6 +100,10 @@ function _generate_snippets()
}
no_autocreate[template_id] = true ;
}
if ( ! gUserSettings["auto-create-national-capabilities-labels"] ) {
no_autocreate.nat_caps_1 = true ;
no_autocreate.nat_caps_2 = true ;
}
function on_snippet_button( $btn, inactive ) {
var template_id = $btn.attr( "data-id" ) ;
@ -114,7 +118,11 @@ function _generate_snippets()
var params = unload_snippet_params( true, template_id ) ;
var snippet_id = template_id ;
var extra_params = {} ;
var player_no = get_player_no_for_element( $btn ) ;
var player_no ;
if ( snippet_id.substring( 0, 9 ) === "nat_caps_" )
player_no = snippet_id.substring( 9 ) ;
else
player_no = get_player_no_for_element( $btn ) ;
var data ;
if ( ["scenario_note","ob_setup","ob_note"].indexOf( template_id ) !== -1 ) {
data = $btn.parent().parent().data( "sortable2-data" ) ;
@ -225,6 +233,8 @@ function _get_raw_content( snippet_id, $btn, params )
return [ "Bazooka", "Range", "TH#" ] ;
if ( snippet_id === "thh" )
return [ "Tank-Hunter Heroes", "Banzai Charge" ] ;
if ( snippet_id.substring( 0, 9 ) === "nat_caps_" )
return [ "Capabilities" ] ;
// handle vehicle/ordnance notes
// NOTE: These were implemented after we added snippet ID's, so there's no need to support legacy labels.

@ -110,6 +110,7 @@ gHelpUrl = "{{url_for('show_help')}}" ;
<script src="{{url_for('static',filename='main.js')}}"></script>
<script src="{{url_for('static',filename='snippets.js')}}"></script>
<script src="{{url_for('static',filename='nat_caps.js')}}"></script>
<script src="{{url_for('static',filename='extras.js')}}"></script>
<script src="{{url_for('static',filename='simple_notes.js')}}"></script>
<script src="{{url_for('static',filename='vo.js')}}"></script>

@ -0,0 +1,70 @@
<!doctype html> <!-- NOTE: For testing porpoises only! -->
<html lang="en">
<head>
<meta charset="utf-8">
<title> National Capabilities: {{NATIONALITY}} </title>
</head>
<body>
<iframe id="results" style="display:none;position:absolute;width:95%;height:95%;border:none;"> </iframe>
<!--FUDGE! We need these to set up parts of the real web page (because snippet generation reads them) -->
<select name="PLAYER_1" style="display:none;">
<option value="{{NATIONALITY}}"> {{NATIONALITY}} </option>
</select>
<button data-id="nat_caps_1" style="display:none;"></button>
</body>
<script src="{{url_for('static',filename='jquery/jquery-3.3.1.min.js')}}"></script>
<script src="{{url_for('static',filename='jinja/jinja.js')}}"></script>
<script src="{{url_for('static',filename='js-cookie/js.cookie.js')}}"></script>
<script src="{{url_for('static',filename='nat_caps.js')}}"></script>
<script src="{{url_for('static',filename='snippets.js')}}"></script>
<script src="{{url_for('static',filename='user_settings.js')}}"></script>
<script src="{{url_for('static',filename='utils.js')}}"></script>