つづき
(6)指揮範囲内の部隊ユニットをレベル2(OOCマーカー有り)にする。
汎用キーコマンドを使い、次の3条件成立で部隊ユニットのレベルを上げる。
・部隊名一致(部隊のOOBidと指揮官のOOB_GB *1) *1汎用属性に登録したもの。
・部隊ユニットのレベルが1である。
・部隊ユニットと指揮官の距離が20HEX以内である。
→20の値は仮の値である。プレイテスト結果で見直す予定である。
処理時間の短縮のためには小さい値が良いと思われる。
遠く離れた部隊は指揮範囲外である事が明らかなので、自動判定の必要性は低い。
(7)指揮範囲内の部隊ユニットをレベル1(OOCマーカー無し)にする。
汎用キーコマンドを使い、次の2条件成立で部隊ユニットのレベルを上げる。
・部隊名一致(部隊のOOBidと指揮官のOOB_GB *1) *1汎用属性に登録したもの。
・部隊ユニットと指揮官の距離が指揮範囲(range)以内である。
(8)上記の(5)から(7)までを一括して処理する。
トリガー動作機能に(5)から(7)までのホットキーを登録する。
→これでctrl+tで指揮範囲の自動判定ができる。
4.build変更プログラムの改修
上記3の機能を持つVASSALを作成する為のbuild変更プログラムを改修する。
(1)改修の内容
下図のようにVASSAL編集機能で変更した上記3の機能を持つVASSALモジュールと
変更前のモジュールを比較する。下図枠内は指揮官の例(上段が変更前、下段が変更後)。
その差分データをbuild変更プログラムに追加する。
(2)改修版プログラムソース
最後に添付する。
5.その他
(1)部隊指揮官以外の指揮官は指揮部範囲を空白にする。
参謀長や副官などは、部隊指揮官の代理として交代したときに指揮範囲を手動で入れる。
なお、臨時の派遣部隊を編成したときには、部隊の指揮官として新規の部隊名を入れ、
派遣部隊も部隊名を変更する。なお、既存の部隊名と重複しないようにする。
例)一部のコサックを派遣部隊とし、副官の1人を指揮官とする。
派遣部隊を編成前 編成後
副官の指揮部隊名と範囲 R0fと空白 R0fDtと3
派遣部隊の部隊名 R0f R0fDt
<個人的な感想>
pythonのbuild変更プログラムは便利である。VASSALの改修を全てのモジュールに反映できる。
#OOC判定用にユニットに情報追加(OOB_Sub)なお、指揮官同士のOOCは除外した。 | |
import xml.etree.ElementTree as ET | |
import xml.dom.minidom as md | |
import re | |
import csv | |
# 師団番号検索パターン | |
pattern = "(.*)_(.*)" | |
# XMLファイルを解析 | |
buid_path=r'D:\DATA2\game\Bataille\Bataille_set\VASSAL\Z_base\Hagelberg_V2R5ext\buildFile' | |
tree = ET.parse(buid_path) | |
# ツリーを取得 | |
root = tree.getroot() | |
#要素を文字列に変換 | |
strxml=ET.tostring(root, 'utf-8').decode() | |
#基本情報ファイルを読み込む | |
read_file=open(r'D:\WORK\temp\BatailleWK\UnitInfo_1813Hagelberg_PrV2.csv', encoding='utf-8') | |
reader= csv.reader(read_file) | |
read_data=list(reader) | |
read_file.close() | |
#陣営、トレイ名称設定 | |
#side='French' | |
side='Allied' | |
Tray_name='Tray_'+side | |
side_name='prototype;'+side+' unit ' | |
side_name2='prototype;'+side+' unit' | |
#初期設定 | |
Deck_xmax=7 | |
Deck_xdist=140 | |
Deck_ydist=140 | |
Deck_xstart=70 | |
Deck_ystart=100 | |
gpid=3000 #トレイが2つの場合、1回めの作成時は2000,2回目は3000 | |
#トレイ共通部セット | |
Tray_header=['']*4 | |
Tray_header[0]=' <VASSAL.build.module.Map allowMultiple="false" backgroundcolor="255,255,204" buttonName="' | |
Tray_header[1]='" changeFormat="$message$" color="0,0,0" createFormat="$pieceName$ created in $location$" edgeHeight="0" edgeWidth="0" hotkey="" icon="" launch="true" mapName="' | |
Tray_header[2]='" markMoved="Never" markUnmovedIcon="/images/unmoved.gif" markUnmovedText="" markUnmovedTooltip="Mark all pieces on this map as not moved" moveKey="" moveToFormat="$pieceName$ moves $previousLocation$ -> $location$ *" moveWithinFormat="$pieceName$ moves $previousLocation$ -> $location$ *" thickness="3">\n <VASSAL.build.module.map.BoardPicker addColumnText="Add column" addRowText="Add row" boardPrompt="Select board" slotHeight="125" slotScale="0.2" slotWidth="450" title="Choose Boards">\n <setup>' | |
Tray_header[3]='BoardPicker tray 0 0</setup>\n <VASSAL.build.module.map.boardPicker.Board height="600" name="tray" reversible="false" width="1900"/>\n </VASSAL.build.module.map.BoardPicker>\n <VASSAL.build.module.map.StackMetrics bottom="40,0" disabled="false" down="37,0" exSepX="10" exSepY="10" top="38,0" unexSepX="4" unexSepY="4" up="39,0"/>\n <VASSAL.build.module.map.ForwardToKeyBuffer/>\n <VASSAL.build.module.map.Scroller/>\n <VASSAL.build.module.map.ForwardToChatter/>\n <VASSAL.build.module.map.MenuDisplayer/>\n <VASSAL.build.module.map.MapCenterer/>\n <VASSAL.build.module.map.StackExpander/>\n <VASSAL.build.module.map.PieceMover/>\n <VASSAL.build.module.map.KeyBufferer/>\n <VASSAL.build.module.map.ImageSaver buttonText="" hotkey="" icon="/images/camera.gif" tooltip="Save Map as PNG image"/>\n <VASSAL.build.module.map.CounterDetailViewer borderWidth="0" counterReportFormat="" delay="700" display="from top-most layer only" emptyHexReportForma="$LocationName$" fgColor="0,0,0" fontSize="9" graphicsZoom="1.0" hotkey="32,130" layerList="" minDisplayPieces="2" propertyFilter="" showDeck="false" showMoveSelectde="false" showNoStack="false" showNonMovable="false" showgraph="true" showgraphsingle="false" showtext="false" showtextsingle="false" summaryReportFormat="$LocationName$" unrotatePieces="false" version="" zoomlevel="1.0"/>\n <VASSAL.build.module.properties.GlobalProperties/>\n <VASSAL.build.module.map.SelectionHighlighters/>\n <VASSAL.build.module.map.HighlightLastMoved color="255,0,0" enabled="true" thickness="2"/>\n' | |
#デッキ共通部セット | |
Deck_header=['']*3 | |
Deck_header[0]=' <VASSAL.build.module.map.DrawPile allowMultiple="false" allowSelect="true" canSave="false" color="0,0,0" countExpressions="" draw="false" drawFaceUp="true" emptyHotkey="" expressionCounting="false" faceDown="Never" faceDownFormat="" height="60" hotkeyOnEmpty="false" maxStack="30" name="' | |
Deck_header[1]='" owningBoard="tray" reshufflable="false" reshuffleCommand="" reshuffleHotkey="" reshuffleMessage="" reshuffleTarget="" restrictExpression="" restrictOption="false" reverseCommand="Reverse" reverseFormat="" reverseHotkey="" reversible="false" selectDisplayProperty="$BasicName$" selectSortProperty="" shuffle="Never" shuffleCommand="Shuffle" shuffleFormat="" shuffleHotkey="" width="120" ' | |
#カード共通部セット | |
Card_header=['']*1 | |
Card_header[0]=' <VASSAL.build.widget.CardSlot entryName="' | |
#歩兵、騎兵 | |
Card_header_InfCav=['']*9 | |
Card_header_InfCav[0]=Card_header[0] | |
Card_header_InfCav[1]='" height="0" width="0">+/null/emb2;Activate;2;;OOC;2;;;2;;IC;50,65;1;false;0;0;,08_OOC40.png;In_cmd,out_cmd;false;OOCstatus;;;false;;1;1;true;65,130;49,65; ' | |
Card_header_InfCav[2]='\\ propertysheet;0Fire~0Melee~0Morale~0Range\/Lancer;Class Properties;;0;;;;67,130\\\\ propertysheet;0Strength~0Status~0OOBid;Properties;;0;;;;80,130\\\\\\ markmoved;moved;56;0;Mark Moved;77,130\\\\\\\\ rotate;24;93,130;91,130;Rotate CW;Rotate CCW;;;\\\\\\\\\\ ' | |
Card_header_InfCav[3]='emb2;Activate;2;;;2;;;2;;;;1;false;0;0;' #裏画像付き | |
Card_header_InfCav[4]='.jpg;;true;SK;;;false;;1;1;false;70,130;;\\\\\\\\\\\\ ' #裏画像付き | |
Card_header_InfCav[5]='piece;;;' | |
Card_header_InfCav[6]='\\\\\\ false\\\\\\\\ 0\\\\\\\\\\ ' | |
Card_header_InfCav[7]='-1\\\\\\\\\\\\ ' #裏画像付き | |
Card_header_InfCav[8]='null;0;0;' | |
#砲兵 | |
Card_header_Art=['']*6 | |
Card_header_Art[0]=Card_header[0] | |
Card_header_Art[1]='" height="0" width="0">+/null/emb2;Activate;2;;OOC;2;;;2;;IC;50,65;1;false;0;0;,08_OOC40.png;In_cmd,out_cmd;false;OOCstatus;;;false;;1;1;true;65,130;49,65; ' | |
Card_header_Art[2]='\\ propertysheet;0Strength~0Status~0OOBid;Properties;;0;;;;80,130\\\\ markmoved;moved;56;0;Mark Moved;77,130\\\\\\ rotate;24;93,130;91,130;Rotate CW;Rotate CCW;;;\\\\\\\\ emb2;Activate;2;;;2;;;2;;;;1;false;0;0;' | |
Card_header_Art[3]='.jpg;;true;BI;;;false;;1;1;false;70,130;;\\\\\\\\\\ ' | |
Card_header_Art[4]='piece;;;' | |
Card_header_Art[5]='\\\\ false\\\\\\ 0\\\\\\\\ -1\\\\\\\\\\ null;0;0;' | |
#指揮官 | |
Card_header_Cmd=['']*5 | |
Card_header_Cmd[0]=Card_header[0] | |
Card_header_Cmd[1]='" height="0" width="0">+/null/macro;Cmdcheck;Trigger;84,130;;;86\\,130,71\\,65,71\\,130;false;;;counted;;;;false;;1;1 globalkey;reset OOC;71,130;50,65;{OOBid == OOB_GB};true;2;true;false;range;reset OOC;-1\\ globalkey;set OOC;71,65;49,65;{OOBid == OOB_GB && OOCstatus_Level==1};true;20;true;true;range;set OOC;-1\\\\ setprop;OOB_GB;false,0,100,false;set value:86\\,130:P\\,{OOB_Sub};set OOBid;Current Zone\/Current Map\\/Module;\\\\\\ ' | |
Card_header_Cmd[2]='\\\\\\\\ propertysheet;0Inf Bonus A\/D~0Cav Bonus~0Art Bous~0Morale Bonus~0OOB_Sub~0range;Class Properties;;0;;;;67,130\\\\\\\\\\ markmoved;moved;56;0;Mark Moved;77,130\\\\\\\\\\\\ rotate;24;93,130;91,130;Rotate CW;Rotate CCW;;;\\\\\\\\\\\\\\ ' | |
Card_header_Cmd[3]='piece;;;' | |
Card_header_Cmd[4]='\\\\\\\\\\ false\\\\\\\\\\\\ 0\\\\\\\\\\\\\\ null;0;0;' | |
#終了部 | |
Card_footer='</VASSAL.build.widget.CardSlot>\n' | |
Deck_footer=' </VASSAL.build.module.map.DrawPile>\n' | |
Tray_footer=' </VASSAL.build.module.Map>\n' | |
File_footer='</VASSAL.launch.BasicModule>' | |
#ファイルの終了を一旦削除 | |
strxml_first=re.sub(File_footer,"",strxml) | |
#Tray追加 | |
strxml_new=strxml_first+Tray_header[0]+Tray_name+Tray_header[1]+Tray_name+Tray_header[2]+Tray_name+Tray_header[3] | |
end_line=int(read_data[0][10])-1 | |
Deck_xnum=0 | |
Deck_ynum=0 | |
Deck_nameold="" | |
Deck_start='No' | |
for i in range(1,end_line): | |
Deck_name=read_data[i][8] | |
if Deck_name !=Deck_nameold : | |
if Deck_start=='Yes': | |
strxml_new=strxml_new+Deck_footer #Deck終了 | |
Deck_nameold=Deck_name | |
Deck_x=Deck_xstart + Deck_xdist*Deck_xnum | |
Deck_y=Deck_ystart + Deck_ydist*Deck_ynum | |
Deck_header[2]='x="'+str(Deck_x)+'" y="'+str(Deck_y)+'">\n' | |
#Deck追加 | |
strxml_new=strxml_new+Deck_header[0]+Deck_name+Deck_header[1]+Deck_header[2] | |
Deck_start='Yes' | |
Deck_xnum+=1 | |
if Deck_xnum>=Deck_xmax: | |
Deck_xnum=0 | |
Deck_ynum+=1 | |
unit_name=read_data[i][0] | |
unit_name2=re.sub('/',"\/",unit_name) #部隊名称で1/LRなど"/"の文字が入る場合の対策。これがないとVASSALでエラーになる。 | |
fire_value=read_data[i][1] | |
fire_value=re.sub('/',"\/",fire_value) #指揮官の歩兵ボーナスで攻撃/防御など"/"の文字が入る場合の対策。これがないとVASSALでエラーになる。 | |
melee_value=read_data[i][2] | |
morale_value=read_data[i][3] | |
range_value=read_data[i][4] | |
uinit_strength=read_data[i][5] | |
unit_imageF=read_data[i][6] | |
unit_imageB=read_data[i][7] | |
unit_type=read_data[i][9] | |
unit_oob=unit_imageF[0:3] | |
d = re.search(pattern, Deck_name) | |
divno = d.group(2) | |
if divno=="0": | |
divno="" | |
oobsub=unit_oob+divno | |
#Card編集 | |
gpid+=1 | |
Card_val_1=unit_name+'" gpid="'+str(gpid) | |
if unit_type=='4inf' or unit_type=='3cav': #歩兵、騎兵の場合 | |
Card_unite=Card_header_InfCav[0]+Card_val_1+Card_header_InfCav[1]+side_name2+Card_header_InfCav[2] | |
if unit_imageB!='': #裏画像あり | |
Card_unite=Card_unite+Card_header_InfCav[3]+unit_imageB+Card_header_InfCav[4] | |
Card_unite=Card_unite+Card_header_InfCav[5]+unit_imageF+'.jpg;'+unit_name2 | |
Card_unite=Card_unite+'/1 \\ '+fire_value+'~'+melee_value+'~'+morale_value+'~'+range_value+'\\\\ '+uinit_strength+'~'+unit_imageF+'~'+oobsub+Card_header_InfCav[6] | |
if unit_imageB!='': #裏画像あり | |
Card_unite=Card_unite+Card_header_InfCav[7] | |
Card_unite=Card_unite+Card_header_InfCav[8]+Card_footer | |
elif unit_type=='2art': #砲兵の場合 | |
Card_unite=Card_header_Art[0]+Card_val_1+Card_header_Art[1]+side_name2+Card_header_Art[2]+unit_imageB+Card_header_Art[3]+Card_header_Art[4]+unit_imageF+'.jpg;'+unit_name2 | |
Card_unite=Card_unite+'/1 \\ '+uinit_strength+'~'+unit_imageF+'~'+oobsub+Card_header_Art[5]+Card_footer | |
elif unit_type=='1cmd': #指揮官の場合 | |
Card_unite=Card_header_Cmd[0]+Card_val_1+Card_header_Cmd[1]+side_name2+Card_header_Cmd[2]+Card_header_Cmd[3]+unit_imageF+'.jpg;'+unit_name2 | |
cmdt=unit_imageB[0:2] | |
if cmdt=="FC" : | |
cmdrange="12" | |
elif cmdt=="FD" : | |
cmdrange="6" | |
elif cmdt=="FB" : | |
cmdrange="4" | |
elif cmdt=="AC" : | |
cmdrange="10" | |
elif cmdt=="AD" : | |
cmdrange="5" | |
elif cmdt=="AB" : | |
cmdrange="3" | |
else: | |
cmdrange="" | |
Card_unite=Card_unite+'/ \\ \\\\ \\\\\\ \\\\\\\\ '+fire_value+'~'+melee_value+'~'+morale_value+'~'+range_value+'~'+oobsub+'~'+cmdrange+Card_header_Cmd[4]+Card_footer | |
#Card追加 | |
strxml_new=strxml_new+Card_unite | |
#データ終了 | |
strxml_new=strxml_new+Deck_footer+Tray_footer+File_footer | |
#文字列を要素に戻す | |
element_new=ET.fromstring(strxml_new) | |
tree_new = ET.ElementTree(element_new) | |
#ファイル出力 | |
tree_new.write(buid_path, encoding="UTF-8", xml_declaration=True) |