diff --git a/1835_20210331_1936_Ulli_Hegemann.rails b/1835_20210331_1936_Ulli_Hegemann.rails new file mode 100644 index 000000000..50ef45890 Binary files /dev/null and b/1835_20210331_1936_Ulli_Hegemann.rails differ diff --git a/1835_20210331_2116_Ulli_Hegemann.xml b/1835_20210331_2116_Ulli_Hegemann.xml new file mode 100644 index 000000000..947750231 --- /dev/null +++ b/1835_20210331_2116_Ulli_Hegemann.xml @@ -0,0 +1,11906 @@ + + + + 0 + 0 + 1835 + 0 + + + + + NumberOfPlayers + 4 + + + Variant + Clemens + + + RouteAwareness + Highlight + + + RouteAlgorithm + Permissive + + + RevenueCalculation + Suggest + + + UnlimitedTiles + No + + + NoMapMode + no + + + FirstRoundSellRestriction + First Round + + + BYFloatsAt + 50% + + + LDIncome + 20M + + + MinorsRequireFloatedBY + yes + + + PrussianReservedIgnored + yes + + + NF_PfB_Westermann + no + + + NetworthHidden + no + + + + + Ulli Hegemann + Volker Schnell + Volker Kuhnle + Jupp Krupp + + + 2.4.0-alpha+ + 2021-03-31 23:16:30 + 9 + + + + + true + 3 + Jupp Krupp + + + + + 4 + M3 + + + + + 0 + 80 + false + false + false + + + + + + + true + 2 + Volker Kuhnle + + + + + 9 + M5 + + + + + 0 + 80 + false + false + false + + + + + + + true + 1 + Volker Schnell + + + + + 1 + M1 + + + + + 0 + 80 + false + false + false + + + + + + + true + 0 + Ulli Hegemann + + + + + 3 + M2 + + + + + 0 + 170 + false + false + false + + + + + + + true + 0 + Ulli Hegemann + + + + + 10 + M6 + + + + + 0 + 80 + false + false + false + + + + + + + true + 1 + Volker Schnell + + + + + 5 + M4 + + + + + 0 + 160 + false + false + false + + + + + + + true + 2 + Volker Kuhnle + + + + + 2 + LD + + + + + 0 + 190 + false + false + false + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + NF + + + + + 0 + 100 + false + false + false + + + + + + + true + 0 + Ulli Hegemann + + + + + 8 + HB + + + + + 0 + 160 + false + false + false + + + + + + + true + 1 + Volker Schnell + + + + + 12 + PfB + + + + + 0 + 150 + false + false + false + + + + + + + true + 2 + Volker Kuhnle + + + + + 7 + BB + + + + + 0 + 130 + false + false + false + + + + + + + true + 3 + Jupp Krupp + + + + + 11 + OBB + + + + + 0 + 120 + false + false + false + + + + + + + true + 3 + Jupp Krupp + + + + + 6 + Bay + + + + + 0 + 184 + false + false + false + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 92 + 10 + BY + Bank_IPO + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 1 + false + 0 + 0 + H2 + 202 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 80 + false + false + 0 + false + false + 80 + 0 + IPO + 2_0 + 2 + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 4 + false + 0 + 0 + E17 + 8 + + + yellow + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 80 + false + false + 0 + false + false + 80 + 0 + IPO + 2_1 + 2 + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 5 + false + 0 + 0 + F14 + 6 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 80 + false + false + 0 + false + false + 80 + 0 + IPO + 2_2 + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 3 + false + 0 + 0 + G5 + 6 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 80 + false + false + 0 + false + false + 80 + 0 + IPO + 2_3 + 2 + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 80 + false + false + 0 + false + false + 80 + 0 + IPO + 2_4 + 2 + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 3 + false + 0 + 0 + D18 + 8 + + + yellow + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 80 + false + false + 0 + false + false + 80 + 0 + IPO + 2_5 + 2 + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 2 + false + 0 + 0 + B10 + 9 + + + yellow + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 80 + false + false + 0 + false + false + 80 + 0 + IPO + 2_6 + 2 + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 4 + false + 0 + 0 + O15 + 202 + + + yellow + 2 + + + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 0 + false + 0 + 0 + N16 + 8 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 2 + false + 2 + 0 + M15 + M15 + 4 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 1 + L14 + L14 + + + + + 1 + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 80 + false + true + 0 + false + false + 80 + 0 + IPO + 2_7 + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 80 + false + false + 0 + false + false + 80 + 0 + IPO + 2_8 + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 120 + false + false + 0 + false + false + 120 + 0 + IPO + 2+2_0 + 2+2 + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 92 + 10 + BY + Bank_IPO + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 92 + 10 + BY + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 0 + false + 0 + 0 + H4 + 69 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 40 + true + 0 + 0 + 0 + 1 + + 1 + + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 1 + false + 0 + 0 + F16 + 8 + + + yellow + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 50 + true + 0 + 0 + 0 + 1 + + 1 + + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 2 + false + 0 + 0 + E13 + 9 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 50 + true + 0 + 0 + 0 + 1 + + 1 + + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 4 + false + 0 + 0 + F4 + 3 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 60 + true + 0 + 0 + 0 + 1 + + 1 + + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 4 + false + 0 + 0 + C19 + 8 + + + yellow + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 50 + true + 0 + 0 + 0 + 1 + + 1 + + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 2 + false + 0 + 0 + A11 + 6 + + + yellow + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 60 + true + 0 + 0 + 0 + 1 + + 1 + + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 5 + false + 0 + 0 + K13 + 8 + + + yellow + 2 + + + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 2 + false + 0 + 0 + K11 + 58 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 110 + true + 0 + 0 + 0 + 2 + + 2 + 0 + + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + 1 + false + 92 + 10 + BY + Bank_IPO + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 92 + 10 + BY + Bank_IPO + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 88 + 10 + SX + Bank_IPO + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 0 + 0 + 92 + 10 + 10 + 1 + BY + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 88 + 10 + SX + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 88 + 10 + SX + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 2 + false + 0 + 0 + J2 + 9 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 40 + true + 0 + 40 + 0 + 1 + + 1 + + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + 2 + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 50 + true + 0 + 50 + 0 + 1 + + 1 + + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 120 + false + false + 0 + false + false + 120 + 0 + IPO + 2+2_1 + 2+2 + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 5 + false + 0 + 0 + D12 + 8 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 50 + true + 0 + 50 + 0 + 1 + + 1 + + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 1 + false + 0 + 0 + F6 + 58 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 60 + true + 0 + 60 + 0 + 1 + + 1 + + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 2 + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 50 + true + 0 + 50 + 0 + 1 + + 1 + + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 2 + false + 0 + 0 + B12 + 58 + + + yellow + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 60 + true + 0 + 60 + 0 + 1 + + 1 + + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 5 + false + 0 + 0 + J10 + 8 + + + yellow + 2 + + + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 2 + false + 0 + 0 + O13 + 8 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + J8 + + + + + 1 + 1 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 160 + true + 0 + 110 + 0 + 2 + + 2 + 0 + + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 120 + false + false + 0 + false + false + 120 + 0 + IPO + 2+2_2 + 2+2 + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 0 + false + 0 + 0 + H16 + 5 + + + yellow + 2 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 3 + false + 0 + 0 + I17 + 56 + + + yellow + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + 2 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 120 + false + true + 0 + false + false + 120 + 0 + IPO + 2+2_3 + 2+2 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 180 + false + false + 0 + false + false + 180 + 0 + IPO + 3_0 + 3 + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + 1 + false + 94 + 10 + BY + Bank_Pool + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 88 + 10 + SX + Bank_IPO + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 88 + 10 + SX + Bank_IPO + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 88 + 10 + SX + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 4 + false + 0 + 0 + H2 + 207 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 50 + true + 0 + 40 + 0 + 1 + + 1 + + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 3 + false + 0 + 0 + E19 + 209 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 130 + true + 0 + 50 + 0 + 1 + + 1 + + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 0 + false + 0 + 0 + F14 + 206 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 70 + true + 0 + 50 + 0 + 1 + + 1 + + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 0 + false + false + 0 + false + false + 85 + 0 + BY + 2+2_0 + 2+2 + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 2 + false + 0 + 0 + G5 + 12 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 80 + true + 0 + 60 + 0 + 1 + + 1 + + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 2 + false + 0 + 0 + F20 + 9 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 70 + true + 0 + 50 + 0 + 1 + + 1 + + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 0 + false + false + 0 + false + false + 85 + 0 + SX + 3_0 + 3 + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 1 + false + 0 + 0 + A11 + 12 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 70 + true + 0 + 60 + 0 + 1 + + 1 + + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 0 + false + false + 0 + false + false + 95 + 0 + M2 + 2+2_1 + 2+2 + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 2 + false + 0 + 0 + J6 + 215 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 190 + true + 0 + 160 + 0 + 2 + + 2 + 0 + + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 180 + false + false + 0 + false + false + 180 + 0 + IPO + 3_1 + 3 + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 1 + false + 0 + 0 + H20 + 202 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + 2 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 60 + true + 0 + 0 + 0 + 2 + + 2 + 0 + + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 180 + false + false + 0 + false + false + 180 + 0 + IPO + 3_2 + 3 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 180 + false + false + 0 + false + false + 180 + 0 + IPO + 3_3 + 3 + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 5 + false + 0 + 0 + G3 + 212 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 70 + true + 0 + 50 + 0 + 1 + + 1 + + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 5 + false + 0 + 0 + D18 + 25 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 70 + true + 0 + 130 + 0 + 1 + + 1 + + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 0 + false + false + 0 + false + false + 1 + 0 + M6 + 2_6 + 2 + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 3 + false + 0 + 0 + D10 + 7 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 150 + true + 0 + 70 + 0 + 1 + + 1 + + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 4 + false + 0 + 0 + H4 + 204 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 100 + true + 0 + 80 + 0 + 1 + + 1 + + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 4 + false + 0 + 0 + H20 + 208 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 180 + true + 0 + 70 + 0 + 1 + + 1 + + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 0 + false + 0 + 0 + B14 + 3 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 90 + true + 0 + 70 + 0 + 1 + + 1 + + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 2 + false + 0 + 0 + N12 + 6 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 270 + true + 0 + 190 + 0 + 2 + + 2 + 0 + + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 4 + false + 0 + 0 + H18 + 8 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + E19 + + + + + 1 + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 280 + true + 0 + 60 + 0 + 2 + + 2 + 0 + + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + 1 + false + 88 + 10 + SX + Bank_IPO + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 88 + 10 + SX + Bank_IPO + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 2 + false + 168 + 20 + BA + Bank_IPO + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 77 + 10 + PR + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 77 + 10 + PR + Bank_IPO + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 84 + 10 + BA + Bank_IPO + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 77 + 10 + PR + Bank_IPO + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 84 + 10 + BA + Bank_IPO + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 0 + 0 + 122 + 10 + 10 + 1 + BY + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 84 + 10 + BA + Bank_IPO + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 112 + 10 + BY + Bank_Pool + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + 2 + false + 168 + 20 + WT + Bank_IPO + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 0 + 0 + 112 + 10 + 10 + 1 + BY + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 84 + 10 + BA + Bank_IPO + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 104 + 10 + BY + Bank_Pool + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + 1 + false + 84 + 10 + WT + Bank_IPO + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 84 + 10 + BA + Bank_IPO + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + 1 + false + 84 + 10 + WT + Bank_IPO + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 0 + false + 0 + 0 + I5 + 8 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 70 + true + 0 + 70 + 0 + 1 + + 1 + + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 0 + false + false + 0 + false + false + 85 + 0 + M4 + 2_3 + 2 + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 1 + false + 0 + 0 + D16 + 9 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 150 + true + 0 + 70 + 0 + 1 + + 1 + + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 0 + false + 0 + 0 + G15 + 58 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 150 + true + 0 + 150 + 0 + 1 + + 1 + + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 0 + false + 0 + 0 + K7 + 8 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 60 + true + 0 + 100 + 0 + 1 + + 1 + + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 5 + false + 0 + 0 + H16 + 205 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 180 + true + 0 + 180 + 0 + 1 + + 1 + + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 5 + false + 0 + 0 + B14 + 87 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 90 + true + 0 + 90 + 0 + 1 + + 1 + + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 0 + false + false + 0 + false + false + 90 + 0 + M2 + 2_1 + 2 + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 1 + false + 0 + 0 + O15 + 207 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 290 + true + 0 + 270 + 0 + 2 + + 2 + 0 + + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 2 + false + 0 + 0 + D14 + 8 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + 2 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 310 + true + 0 + 280 + 0 + 2 + + 2 + 0 + + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 0 + false + false + 0 + false + false + 1 + 0 + M5 + 2_5 + 2 + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + BA + + + + + 0 + 4 + false + 4 + 0 + L6 + L6 + + + BA + 1 + + + BA:1 + 210 + + + green + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + BA + + + + + 0 + 3 + false + 0 + 0 + I3 + 201 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + BA + + + + + 0 + H2 + + + + + 1 + 1 + + + + + + + true + 1 + Volker Schnell + + + + + BA + + + + + 0 + 270 + false + true + 0 + false + false + 270 + 0 + IPO + 3+3_0 + 3+3 + + + + + + + true + 1 + Volker Schnell + + + + + BA + + + + + 0 + 0 + false + false + 0 + false + false + 1 + 0 + M1 + 2_0 + 2 + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 0 + false + 0 + 0 + I3 + 208 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 80 + true + 0 + 70 + 0 + 1 + + 1 + + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 2 + false + 0 + 0 + F20 + 23 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 80 + true + 0 + 150 + 0 + 1 + + 1 + + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 270 + false + false + 0 + false + false + 270 + 0 + IPO + 3+3_1 + 3+3 + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 0 + false + 0 + 0 + H14 + 9 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 150 + true + 0 + 150 + 0 + 1 + + 1 + + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 4 + false + 0 + 0 + F4 + 87 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 60 + true + 0 + 60 + 0 + 1 + + 1 + + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 4 + false + 0 + 0 + H18 + 16 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 120 + true + 0 + 180 + 0 + 1 + + 1 + + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 0 + false + false + 0 + false + false + 240 + 0 + SX + 2_5 + 2 + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 2 + false + 0 + 0 + C15 + 9 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 90 + true + 0 + 90 + 0 + 1 + + 1 + + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 1 + false + 0 + 0 + K11 + 204 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 290 + true + 0 + 290 + 0 + 2 + + 2 + 0 + + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 3 + false + 0 + 0 + H14 + 27 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + 2 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 310 + true + 0 + 310 + 0 + 2 + + 2 + 0 + + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 270 + false + false + 0 + false + false + 270 + 0 + IPO + 3+3_2 + 3+3 + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + BA + + + + + 0 + 2 + false + 0 + 0 + J2 + 27 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + BA + + + + + 0 + 220 + true + 0 + 0 + 0 + 2 + + 2 + 0 + + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 77 + 10 + PR + Bank_IPO + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 84 + 10 + BA + Bank_IPO + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 84 + 20 + BA + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + 1 + false + 84 + 10 + WT + Bank_IPO + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 2 + false + 168 + 20 + HE + Bank_IPO + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + 1 + false + 84 + 10 + WT + Bank_IPO + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 84 + 10 + HE + Bank_IPO + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + 1 + false + 207 + 10 + BY + Player_Ulli Hegemann + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 0 + 0 + 138 + 10 + 10 + 1 + BY + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 84 + 10 + HE + Bank_IPO + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 126 + 10 + BY + Bank_Pool + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 84 + 10 + HE + Bank_IPO + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 84 + 10 + HE + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + 1 + false + 189 + 10 + BY + Player_Volker Schnell + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 84 + 10 + HE + Bank_IPO + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 126 + 20 + BA + Player_Volker Kuhnle + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 84 + 10 + WT + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 84 + 10 + HE + Bank_IPO + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 84 + 20 + HE + Bank_IPO + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 84 + 10 + WT + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 84 + 20 + WT + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 2 + false + 160 + 20 + MS + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 0 + 0 + 126 + 10 + 10 + 1 + BY + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 80 + 20 + MS + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 0 + 0 + 126 + 10 + 10 + 1 + BY + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 80 + 20 + MS + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + 0 + 0 + 122 + 10 + 10 + 1 + SX + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + 1 + false + 126 + 10 + BY + Bank_Pool + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 112 + 10 + SX + Bank_Pool + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 80 + 10 + MS + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 5 + false + 0 + 0 + I5 + 16 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 80 + true + 0 + 80 + 0 + 1 + + 1 + + + + + + + + true + 1 + Volker Schnell + + + + + M1 + + + + + 0 + 0 + false + false + 0 + false + false + 81 + 0 + M4 + 2_4 + 2 + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 1 + false + 0 + 0 + D16 + 23 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + + + + + 0 + 220 + true + 0 + 80 + 0 + 1 + + 1 + + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 0 + false + 0 + 0 + I13 + 4 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + 0 + 160 + true + 0 + 150 + 0 + 1 + + 1 + + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 4 + false + 0 + 0 + E7 + 8 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + M4 + + + + + 0 + 0 + false + false + 0 + false + false + 326 + 0 + BA + 2_0 + 2 + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 1 + false + 0 + 0 + B12 + 203 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + M5 + + + + + 0 + 190 + true + 0 + 120 + 0 + 1 + + 1 + + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 1 + false + 0 + 0 + B16 + 4 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + M6 + + + + + 0 + 90 + true + 0 + 90 + 0 + 1 + + 1 + + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 0 + false + 0 + 0 + L10 + 9 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 290 + true + 0 + 290 + 0 + 2 + + 2 + 0 + + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 5 + false + 0 + 0 + B18 + 8 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + 2 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 430 + true + 0 + 310 + 0 + 2 + + 2 + 0 + + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + BA + + + + + 0 + 2 + false + 0 + 0 + K5 + 9 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + BA + + + + + 0 + 140 + true + 0 + 220 + 0 + 2 + + 2 + 0 + + + + + + + + true + 1 + Volker Schnell + + + + + BA + + + + + 0 + 360 + false + false + 0 + false + false + 360 + 0 + IPO + 4_0 + 4 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + true + 2+2_3 + + 2+2_3 + 3_2 + 3+3_2 + + + + + + + + true + 0 + Ulli Hegemann + + + + + M2 + M2 + + + + + + + true + 0 + Ulli Hegemann + + + + + HB,M6 + + + + + + + + true + 1 + Volker Schnell + + + + + M1,M4 + M1,M4 + + + + + + + true + 2 + Volker Kuhnle + + + + + BB,M5 + + + + + + + + true + 3 + Jupp Krupp + + + + + M3 + + + + + + + + true + 0 + Ulli Hegemann + + + + + BA + + + + + 0 + 360 + false + false + 0 + false + false + 360 + 0 + IPO + 4_1 + 4 + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + WT + + + + + 0 + 0 + false + 0 + 0 + M9 + 6 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + WT + + + + + 0 + 360 + false + true + 0 + false + false + 360 + 0 + IPO + 4_2 + 4 + + + + + + + true + 3 + Jupp Krupp + + + + + WT + + + + + 0 + 440 + false + false + 0 + false + false + 440 + 0 + IPO + 4+4_0 + 4+4 + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + HE + + + + + 0 + 0 + false + 0 + 0 + K7 + 24 + + + green + 1 + + + yellow + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + 2 + + + + + + + true + 0 + Ulli Hegemann + + + + + HE + + + + + 0 + 500 + false + true + 0 + false + false + 500 + 0 + IPO + 5_0 + 5 + + + + + + + true + 1 + Volker Schnell + + + + + BA + + + + + true + 3+3_0 + + 3+3_0 + 4_0 + + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + true + 3_2 + + 3_2 + 3+3_2 + + + + + + + + true + 0 + Ulli Hegemann + + + + + HE + + + + + 0 + 0 + false + false + 0 + false + false + 40 + 0 + PR + 3+3_1 + 3+3 + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + MS + + + + + 0 + 0 + false + 0 + 0 + E19 + 220 + + + green + 1 + + + yellow + 1 + + + brown + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + MS + + + + + 0 + E19 + + + + + 1 + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + MS + + + + + 0 + 500 + false + true + 20 + false + true + 500 + 0 + IPO + 5_1 + 5 + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + PR + + + + + 0 + 5 + false + 0 + 0 + I5 + 43 + + + green + 1 + + + yellow + 1 + + + brown + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + 2 + + + + + + + true + 0 + Ulli Hegemann + + + + + PR + + + + + 0 + 140 + true + 0 + 0 + 0 + 2 + + 2 + 0 + + + + + + + + true + 0 + Ulli Hegemann + + + + + PR + + + + + 0 + 600 + false + false + 0 + false + false + 600 + 0 + IPO + 5+5_0 + 5+5 + + + + + + + true + 0 + Ulli Hegemann + + + + + PR + + + + + 0 + 600 + false + false + 0 + false + false + 600 + 0 + IPO + 6_0 + 6 + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 0 + false + 0 + 0 + J12 + 9 + + + green + 1 + + + yellow + 1 + + + brown + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 0 + false + false + 0 + false + false + 298 + 0 + WT + 4_2 + 4 + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 0 + false + 0 + 0 + C11 + 221 + + + green + 1 + + + yellow + 1 + + + brown + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + 2 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 190 + true + 0 + 430 + 0 + 2 + + 2 + 0 + + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + BA + + + + + 0 + 1 + false + 0 + 0 + G3 + 218 + + + green + 1 + + + yellow + 1 + + + brown + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + BA + + + + + 0 + 270 + true + 0 + 140 + 0 + 2 + + 2 + 0 + + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + WT + + + + + 0 + 0 + false + 0 + 0 + F14 + 63 + + + green + 1 + + + yellow + 1 + + + brown + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + WT + + + + + 0 + F14 + + + + + 1 + 1 + + + + + + + true + 3 + Jupp Krupp + + + + + WT + + + + + 0 + 220 + true + 0 + 0 + 0 + 2 + + 2 + 0 + + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + HE + + + + + 0 + 0 + false + 0 + 0 + G5 + 63 + + + green + 1 + + + yellow + 1 + + + brown + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + HE + + + + + 0 + G5 + + + + + 1 + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + HE + + + + + 0 + 310 + true + 0 + 0 + 0 + 2 + + 2 + 0 + + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + MS + + + + + 0 + 4 + false + 0 + 0 + H20 + 216 + + + green + 1 + + + yellow + 1 + + + brown + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + MS + + + + + 0 + 240 + true + 0 + 0 + 0 + 2 + + 2 + 0 + + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + 1 + false + 126 + 10 + BY + Bank_Pool + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + 2 + 0 + 0 + 152 + 10 + 10 + 1 + SX + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 129 + 20 + HE + Player_Volker Schnell + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 138 + 10 + SX + Bank_Pool + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 129 + 10 + PR + Player_Volker Kuhnle + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 138 + 10 + SX + Bank_Pool + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 80 + 10 + MS + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + 1 + false + 129 + 20 + WT + Player_Volker Kuhnle + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 129 + 10 + PR + Player_Volker Schnell + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 2 + false + 160 + 20 + OL + Bank_IPO + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 80 + 10 + MS + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 0 + 0 + 138 + 10 + 10 + 1 + SX + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + 1 + false + 129 + 10 + PR + Player_Volker Kuhnle + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 80 + 20 + OL + Bank_IPO + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 126 + 10 + SX + Bank_Pool + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 80 + 20 + OL + Bank_IPO + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + 1 + false + 80 + 10 + MS + Bank_IPO + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 0 + 0 + 86 + 5 + 5 + 1 + PR + + + + + + + true + 1 + Volker Schnell + + + + + 1 + 1 + false + 80 + 10 + OL + Bank_IPO + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + 1 + false + 86 + 5 + PR + Bank_Pool + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 0 + Ulli Hegemann + + + + + 1 + + + + + + + true + 1 + Volker Schnell + + + + + 1 + + + + + + + true + 2 + Volker Kuhnle + + + + + 1 + + + + + + + true + 3 + Jupp Krupp + + + + + 1 + + + + + + + true + 0 + Ulli Hegemann + + + + + PR + + + + + 0 + 0 + false + 0 + 0 + I3 + 216 + + + green + 1 + + + yellow + 1 + + + brown + 1 + + + + + + + + + true + 0 + Ulli Hegemann + + + + + 2 + + + + + + + true + 0 + Ulli Hegemann + + + + + PR + + + + + 0 + 530 + true + 0 + 140 + 0 + 2 + + 2 + 0 + + + + + + + + true + 0 + Ulli Hegemann + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 3 + false + 0 + 0 + H14 + 41 + + + green + 1 + + + yellow + 1 + + + brown + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 160 + true + 0 + 0 + 0 + 2 + + 2 + 0 + + + + + + + + true + 3 + Jupp Krupp + + + + + BY + + + + + 0 + 0 + false + false + 0 + false + false + 1 + 0 + WT + 4+4_0 + 4+4 + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 0 + false + 0 + 0 + C19 + 25 + + + green + 1 + + + yellow + 1 + + + brown + 1 + + + + + + + + + true + 2 + Volker Kuhnle + + + + + 2 + + + + + + + true + 2 + Volker Kuhnle + + + + + SX + + + + + 0 + 200 + true + 0 + 190 + 0 + 2 + + 2 + 0 + + + + + + + + true + 2 + Volker Kuhnle + + + + + 0 + + + + + + + true + 1 + Volker Schnell + + + + + BA + + + + + 0 + 1 + false + 0 + 0 + E9 + 8 + + + green + 1 + + + yellow + 1 + + + brown + 1 + + + + + + + + + true + 1 + Volker Schnell + + + + + BA + + + + + 0 + 300 + true + 0 + 270 + 0 + 2 + + 2 + 0 + + + + + + + + true + 1 + Volker Schnell + + + + + 0 + + + + + + + true + 3 + Jupp Krupp + + + + + WT + + + + + 0 + 0 + false + 0 + 0 + H16 + 63 + + + green + 1 + + + yellow + 1 + + + brown + 1 + + + + + + + + + true + 3 + Jupp Krupp + + + + + WT + + + + + 0 + 600 + false + true + 401 + false + true + 600 + 0 + IPO + 6_1 + 6 + + + + + + + true + 3 + Jupp Krupp + + + + + 2 + 0 + 0 + 106 + 5 + 5 + 1 + PR + + + + + + + true + 3 + Jupp Krupp + + + + + 0 + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index cb2c92c93..93a9ff326 100644 --- a/build.gradle +++ b/build.gradle @@ -74,6 +74,8 @@ dependencies { implementation 'org.apache.commons:commons-text:1.9' // https://www.jetbrains.com/help/idea/annotating-source-code.html implementation 'org.jetbrains:annotations:20.1.0' + // https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream + implementation group: 'com.thoughtworks.xstream', name: 'xstream', version: '1.4.16' testImplementation 'junit:junit:4.13.2' testImplementation 'org.easytesting:fest-assert-core:2.0M10' diff --git a/src/main/java/net/sf/rails/common/GameData.java b/src/main/java/net/sf/rails/common/GameData.java index 7b4a6790a..eadf192f5 100644 --- a/src/main/java/net/sf/rails/common/GameData.java +++ b/src/main/java/net/sf/rails/common/GameData.java @@ -1,5 +1,6 @@ package net.sf.rails.common; +import java.util.ArrayList; import java.util.List; public class GameData { @@ -14,7 +15,7 @@ private GameData(GameInfo game, GameOptionsSet gameOptions, List players this.game = game; this.gameOptions = gameOptions; - this.players = players; + this.players = new ArrayList<>(players); } public static GameData create(GameInfo game, GameOptionsSet.Builder gameOptions, List players) { diff --git a/src/main/java/net/sf/rails/game/GameManager.java b/src/main/java/net/sf/rails/game/GameManager.java index 589a27cec..86a6b174f 100644 --- a/src/main/java/net/sf/rails/game/GameManager.java +++ b/src/main/java/net/sf/rails/game/GameManager.java @@ -16,9 +16,7 @@ import net.sf.rails.game.state.*; import net.sf.rails.game.state.Currency; import net.sf.rails.ui.swing.GameUIManager; -import net.sf.rails.util.GameLoader; -import net.sf.rails.util.GameSaver; -import net.sf.rails.util.Util; +import net.sf.rails.util.*; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -907,9 +905,16 @@ private boolean processGameActions(GameAction gameAction) { ChangeStack changeStack = getRoot().getStateManager().getChangeStack(); int index = gameAction.getmoveStackIndex(); switch (gameAction.getMode()) { - case SAVE: - result = save(gameAction); + case XML_SAVE: { + IGameSaver gameSaver = new XmlGameSaver(getRoot().getGameData(), executedActions.view()); + result = save(gameAction, gameSaver); break; + } + case SAVE: { + IGameSaver gameSaver = new GameSaver(getRoot().getGameData(), executedActions.view()); + result = save(gameAction, gameSaver); + break; + } case RELOAD: result = reload(gameAction); break; @@ -1035,8 +1040,7 @@ protected void recoverySave() { } } - protected boolean save(GameAction saveAction) { - GameSaver gameSaver = new GameSaver(getRoot().getGameData(), executedActions.view()); + protected boolean save(GameAction saveAction, IGameSaver gameSaver) { File file = new File(saveAction.getFilepath()); try { gameSaver.saveGame(file); diff --git a/src/main/java/net/sf/rails/game/PlayerManager.java b/src/main/java/net/sf/rails/game/PlayerManager.java index 4f797fa6a..ad036cc8a 100644 --- a/src/main/java/net/sf/rails/game/PlayerManager.java +++ b/src/main/java/net/sf/rails/game/PlayerManager.java @@ -92,7 +92,7 @@ public void initPlayers(List playerNames, Bank bank) { playerIndex, player.getId())); } - this.playerNames = Collections.unmodifiableMap(playerNamesBuilder); + this.playerNames = new HashMap<>(playerNamesBuilder); ReportBuffer.add(this, LocalText.getText("PlayerCash", cashText)); ReportBuffer.add(this, LocalText.getText("BankHas", Bank.format(this, bank.getCash()))); diff --git a/src/main/java/net/sf/rails/ui/swing/StatusWindow.java b/src/main/java/net/sf/rails/ui/swing/StatusWindow.java index fa0d1141c..488799a91 100644 --- a/src/main/java/net/sf/rails/ui/swing/StatusWindow.java +++ b/src/main/java/net/sf/rails/ui/swing/StatusWindow.java @@ -19,6 +19,7 @@ import javax.swing.filechooser.FileFilter; import net.sf.rails.util.Util; +import net.sf.rails.util.XmlGameLoader; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,8 +64,10 @@ public class StatusWindow extends JFrame implements ActionListener, KeyListener, protected static final String NEW_CMD = "New"; protected static final String LOAD_CMD = "Load"; + protected static final String XML_LOAD_CMD = "XML-Load"; protected static final String SAVE_CMD = "Save"; + protected static final String XML_SAVE_CMD = "XML-Save"; protected static final String RELOAD_CMD = "Reload"; @@ -152,6 +155,14 @@ public void initMenu() { actionMenuItem.setPossibleAction(new GameAction(gameUIManager.getRoot(), GameAction.Mode.LOAD)); fileMenu.add(actionMenuItem); + actionMenuItem = new ActionMenuItem(XML_LOAD_CMD); + actionMenuItem.setActionCommand(XML_LOAD_CMD); + actionMenuItem.addActionListener(this); + actionMenuItem.setEnabled(true); + actionMenuItem.setPossibleAction(new GameAction(gameUIManager.getRoot(), GameAction.Mode.LOAD)); + fileMenu.add(actionMenuItem); + + actionMenuItem = new ActionMenuItem(LocalText.getText("SAVE")); actionMenuItem.setActionCommand(SAVE_CMD); actionMenuItem.setMnemonic(KeyEvent.VK_S); @@ -161,6 +172,13 @@ public void initMenu() { actionMenuItem.setPossibleAction(new GameAction(gameUIManager.getRoot(), GameAction.Mode.SAVE)); fileMenu.add(actionMenuItem); + actionMenuItem = new ActionMenuItem(XML_SAVE_CMD); + actionMenuItem.setActionCommand(XML_SAVE_CMD); + actionMenuItem.addActionListener(this); + actionMenuItem.setEnabled(true); + actionMenuItem.setPossibleAction(new GameAction(gameUIManager.getRoot(), GameAction.Mode.XML_SAVE)); + fileMenu.add(actionMenuItem); + actionMenuItem = new ActionMenuItem(LocalText.getText("Reload")); actionMenuItem.setActionCommand(RELOAD_CMD); actionMenuItem.setMnemonic(KeyEvent.VK_R); @@ -611,12 +629,14 @@ public void updateStatus(boolean myTurn) { toFront(); } - public void disableButtons () { + public void disableButtons() { passButton.setEnabled(false); autopassButton.setEnabled(false); } - /** Stub, may be overridden in game-specific subclasses */ + /** + * Stub, may be overridden in game-specific subclasses + */ protected boolean updateGameSpecificSettings() { return false; } @@ -673,9 +693,9 @@ public void actionPerformed(ActionEvent actor) { } else if (command.equals(QUIT_CMD)) { gameUIManager.terminate(); - } else if ( command.equals(NEW_CMD) ) { + } else if (command.equals(NEW_CMD)) { // TODO - } else if ( command.equals(LOAD_CMD) ) { + } else if (command.equals(LOAD_CMD)) { // TODO: does this really belong here? String saveDirectory = Config.get("save.directory"); JFileChooser jfc = new JFileChooser(); @@ -705,6 +725,36 @@ public String getDescription() { GameLoader.loadAndStartGame(selectedFile); }).start(); } + } else if (command.equals(XML_LOAD_CMD)) { + // TODO: does this really belong here? + String saveDirectory = Config.get("save.directory"); + JFileChooser jfc = new JFileChooser(); + jfc.setCurrentDirectory(new File(saveDirectory)); + jfc.setFileFilter(new FileFilter() { + @Override + public boolean accept(File f) { + // TODO: need to filter like GameSetupController.isOurs() does + return true; + } + + @Override + public String getDescription() { + return null; + } + }); + + if (jfc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + // close the existing game + + final File selectedFile = jfc.getSelectedFile(); + //start in new thread so that swing thread is not used for game setup + new Thread(() -> { + // close the existing game (which ironically will include us + gameUIManager.closeGame(); + // start the new game + XmlGameLoader.loadAndStartGame(selectedFile); + }).start(); + } } else if (command.equals(REPORT_CMD)) { gameUIManager.reportWindow.setVisible(((JMenuItem) actor.getSource()).isSelected()); gameUIManager.reportWindow.scrollDown(); @@ -718,28 +768,29 @@ public String getDescription() { gameUIManager.autoSaveLoadGame(); } else if (command.equals(SAVESTATUS_CMD)) { gameUIManager.saveGameStatus(); - } else if ( command.equals("Save Logs")) { + } else if (command.equals("Save Logs")) { gameUIManager.saveLogs(); } else if (executedAction == null) { ; } else if (executedAction instanceof GameAction) { switch (((GameAction) executedAction).getMode()) { - case SAVE: - gameUIManager.saveGame((GameAction) executedAction); - break; - case RELOAD: - gameUIManager.reloadGame((GameAction) executedAction); - break; - case EXPORT: - gameUIManager.exportGame((GameAction) executedAction); - break; - default: - process(executedAction); - break; + case XML_SAVE: + case SAVE: + gameUIManager.saveGame((GameAction) executedAction); + break; + case RELOAD: + gameUIManager.reloadGame((GameAction) executedAction); + break; + case EXPORT: + gameUIManager.exportGame((GameAction) executedAction); + break; + default: + process(executedAction); + break; } } else { // Unknown action, let UIManager catch it - process (executedAction); + process(executedAction); } } @@ -760,7 +811,7 @@ public boolean processImmediateAction() { // so that it's not going to loop. DiscardTrain nextAction = (DiscardTrain) immediateAction; immediateAction = null; - gameUIManager.discardTrains (nextAction); + gameUIManager.discardTrains(nextAction); } return true; } @@ -835,7 +886,7 @@ public void endOfGame() { gameUIManager.orWindow.finish(); } - public Player getCurrentPlayer () { + public Player getCurrentPlayer() { return gameUIManager.getCurrentPlayer(); } @@ -860,7 +911,7 @@ public void endOfGameReport() { List gameReport = gm.getGameReport(); Collections.reverse(gameReport); StringBuilder report = new StringBuilder(); - for (String s:gameReport) { + for (String s : gameReport) { report.insert(0, s + "\n"); JOptionPane.showMessageDialog(this, report, @@ -872,16 +923,19 @@ public void endOfGameReport() { } @Override - public void keyReleased(KeyEvent e) {} + public void keyReleased(KeyEvent e) { + } @Override - public void keyPressed(KeyEvent e) {} + public void keyPressed(KeyEvent e) { + } @Override - public void keyTyped(KeyEvent e) {} + public void keyTyped(KeyEvent e) { + } public void updatePlayerOrder(List newPlayerNames) { - gameStatus.updatePlayerOrder(newPlayerNames); + gameStatus.updatePlayerOrder(newPlayerNames); } diff --git a/src/main/java/net/sf/rails/util/GameIOData.java b/src/main/java/net/sf/rails/util/GameIOData.java index aeca1dfcf..a0207244f 100644 --- a/src/main/java/net/sf/rails/util/GameIOData.java +++ b/src/main/java/net/sf/rails/util/GameIOData.java @@ -1,5 +1,6 @@ package net.sf.rails.util; +import java.util.ArrayList; import java.util.List; import rails.game.action.PossibleAction; @@ -23,7 +24,7 @@ class GameIOData { this.version = version; this.date = date; this.fileVersionID = fileVersionID; - this.actions = actions; + this.actions = new ArrayList<>(actions); } GameIOData() {} @@ -62,7 +63,7 @@ long getFileVersionID() { } void setActions(List actions) { - this.actions = actions; + this.actions = new ArrayList<>(actions); } List getActions() { diff --git a/src/main/java/net/sf/rails/util/GameSaver.java b/src/main/java/net/sf/rails/util/GameSaver.java index a0c0261f6..a796994a5 100644 --- a/src/main/java/net/sf/rails/util/GameSaver.java +++ b/src/main/java/net/sf/rails/util/GameSaver.java @@ -25,7 +25,7 @@ /** * GameLoader is responsible to load a saved Rails game */ -public class GameSaver { +public class GameSaver implements IGameSaver { private static final Logger log = LoggerFactory.getLogger(GameSaver.class); diff --git a/src/main/java/net/sf/rails/util/IGameSaver.java b/src/main/java/net/sf/rails/util/IGameSaver.java new file mode 100644 index 000000000..c13879b0b --- /dev/null +++ b/src/main/java/net/sf/rails/util/IGameSaver.java @@ -0,0 +1,8 @@ +package net.sf.rails.util; + +import java.io.File; +import java.io.IOException; + +public interface IGameSaver { + void saveGame(File file) throws IOException; +} diff --git a/src/main/java/net/sf/rails/util/XmlConverter.java b/src/main/java/net/sf/rails/util/XmlConverter.java new file mode 100644 index 000000000..fcd4bf184 --- /dev/null +++ b/src/main/java/net/sf/rails/util/XmlConverter.java @@ -0,0 +1,35 @@ +package net.sf.rails.util; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.filefilter.DirectoryFileFilter; +import org.apache.commons.io.filefilter.RegexFileFilter; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; + +public class XmlConverter { + public static void main(String[] args) { + Collection railsFiles = FileUtils.listFiles( + new File("src/test/resources"), + new RegexFileFilter("(.+).rails"), + DirectoryFileFilter.DIRECTORY + ); + + for (File file : railsFiles) { + System.out.println(file.toString()); + + GameLoader loader = new GameLoader(); + + loader.createFromFile(file); + + XmlGameSaver saver = new XmlGameSaver(loader); + + try { + saver.saveGame(file); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/net/sf/rails/util/XmlGameLoader.java b/src/main/java/net/sf/rails/util/XmlGameLoader.java new file mode 100644 index 000000000..7e825151d --- /dev/null +++ b/src/main/java/net/sf/rails/util/XmlGameLoader.java @@ -0,0 +1,244 @@ +package net.sf.rails.util; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.converters.collections.CollectionConverter; +import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; +import com.thoughtworks.xstream.converters.reflection.ReflectionConverter; +import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; +import net.sf.rails.common.GameOptionsSet; +import net.sf.rails.common.GuiDef; +import net.sf.rails.common.LocalText; +import net.sf.rails.common.parser.ConfigurationException; +import net.sf.rails.common.parser.GameOptionsParser; +import net.sf.rails.game.GameManager; +import net.sf.rails.game.RailsRoot; +import net.sf.rails.ui.swing.GameUIManager; +import net.sf.rails.ui.swing.SplashWindow; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import rails.game.action.PossibleAction; + +import javax.swing.*; +import java.io.EOFException; +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.SortedMap; + +/** + * GameLoader is responsible to load a saved Rails game + */ +public class XmlGameLoader { + + private static final Logger log = LoggerFactory.getLogger(XmlGameLoader.class); + + private GameIOData gameIOData; + + // object data + private RailsRoot railsRoot = null; + private Exception exception = null; + + public XmlGameLoader() { + // do nothing + } + + public static void loadAndStartGame(File gameFile) { + SplashWindow splashWindow = new SplashWindow(true, gameFile.getAbsolutePath()); + splashWindow.notifyOfStep(SplashWindow.STEP_LOAD_GAME); + + // check to see if we were passed in a last_rails file + if (GameUIManager.DEFAULT_SAVE_POLLING_EXTENSION.equals(StringUtils.substringAfterLast(gameFile.getName(), "."))) { + // read the filename from the last rails file + log.debug("loading current game file from last_rails {}", gameFile); + try { + String gameFileStr = FileUtils.readFileToString(gameFile, StandardCharsets.ISO_8859_1).trim(); + gameFile = new File(gameFile.getParentFile(), gameFileStr); + } catch (IOException e) { + log.warn("unable to load {}", gameFile); + return; + } + } + + // use gameLoader instance to start game + XmlGameLoader gameLoader = new XmlGameLoader(); + if (!gameLoader.createFromFile(gameFile)) { + Exception e = gameLoader.getException(); + log.error("Game load failed", e); + if (e instanceof RailsReplayException) { + String title = LocalText.getText("LOAD_INTERRUPTED_TITLE"); + String message = LocalText.getText("LOAD_INTERRUPTED_MESSAGE", e.getMessage()); + JOptionPane.showMessageDialog(splashWindow.getWindow(), message, title, JOptionPane.ERROR_MESSAGE); + } else { + String title = LocalText.getText("LOAD_FAILED_TITLE"); + String message = LocalText.getText("LOAD_FAILED_MESSAGE", e.getMessage()); + JOptionPane.showMessageDialog(splashWindow.getWindow(), message, title, JOptionPane.ERROR_MESSAGE); + // in this case start of game cannot continued + return; + } + } + + GameUIManager gameUIManager = startGameUIManager(gameLoader.getRoot(), true, splashWindow); + + gameUIManager.setGameFile(gameFile); + gameUIManager.startLoadedGame(); + + splashWindow.finalizeGameInit(); + gameUIManager.notifyOfSplashFinalization(); + } + + public static GameUIManager startGameUIManager(RailsRoot game, boolean wasLoaded, SplashWindow splashWindow) { + // TODO: Replace that with a Configure method + GameManager gameManager = game.getGameManager(); + String gameUIManagerClassName = gameManager.getClassName(GuiDef.ClassName.GAME_UI_MANAGER); + GameUIManager gameUIManager = null; + try { + Class gameUIManagerClass = Class.forName(gameUIManagerClassName).asSubclass(GameUIManager.class); + gameUIManager = gameUIManagerClass.newInstance(); + gameUIManager.init(game, wasLoaded, splashWindow); + } catch (Exception e) { + log.error("Cannot instantiate class {}", gameUIManagerClassName, e); + System.exit(1); + } + return gameUIManager; + } + + // FIXME: Rails 2.0 add undefined attribute to allow + // deviations from undefined to default values + private GameOptionsSet.Builder loadDefaultGameOptions(String gameName) { + log.debug("Load default Game Options of {}", gameName); + GameOptionsSet.Builder loadGameOptions = null; + try { + loadGameOptions = GameOptionsParser.load(gameName); + } catch (ConfigurationException e) { + log.error(e.getMessage()); + loadGameOptions = GameOptionsSet.builder(); + } + return loadGameOptions; + } + + /** + * Load the gameData from file + * + * @param gameFile + */ + @SuppressWarnings("unchecked") + public void loadGameData(File gameFile) throws Exception { + log.info("Loading game from file {}", gameFile.getCanonicalPath()); + + final XStream xStream = new XStream(); + + this.gameIOData = (GameIOData) xStream.fromXML(gameFile); + } + + /** + * Convert the gameData + * Requires successful load of gameData + */ + public void convertGameData() { + for (PossibleAction action : gameIOData.getActions()) { + action.applyRailsRoot(railsRoot); + } + } + + /** + * @return false if exception occurred + */ + public boolean replayGame() { + GameManager gameManager = railsRoot.getGameManager(); + log.debug("Starting to execute loaded actions"); + gameManager.setReloading(true); + + int count = 0; + if (gameIOData.getActions() != null) { + // set possible actions for first action + gameManager.getCurrentRound().setPossibleActions(); + for (PossibleAction action : gameIOData.getActions()) { + count++; + if (!gameManager.processOnReload(action)) { + log.warn("Replay of game interrupted at action " + count); + String message = LocalText.getText("LoadInterrupted", count); + exception = new RailsReplayException(message); + break; + } + } + } + + gameManager.setReloading(false); + + // FIXME (Rails2.0): CommentItems have to be replaced + // ReportBuffer.setCommentItems(gameData.userComments); + + // callback to GameManager + gameManager.finishLoading(); + // return true if no exception occurred + return (exception == null); + } + + public RailsRoot getRoot() { + return railsRoot; + } + + public Exception getException() { + return exception; + } + + public List getActions() { + return gameIOData.getActions(); + } + + public String getGameDataAsText() { + return gameIOData.metaDataAsText() + gameIOData.gameOptionsAsText() + gameIOData.playerNamesAsText(); + } + + /** + * @param gameFile + * @return false if exception occurred + */ + public boolean createFromFile(File gameFile) { + try { + // 1st: loadGameData + loadGameData(gameFile); + + // 2nd: create game + railsRoot = RailsRoot.create(gameIOData.getGameData()); + + // 3rd: prepare game + convertGameData(); + + // 4th: start game + railsRoot.start(); + + // 5th: replay game + return replayGame(); + } catch (Exception e) { + e.printStackTrace(); + log.debug("Exception during createFromFile in gameLoader ", e); + exception = e; + return false; + } + } + + public boolean reloadGameFromFile(RailsRoot root, File file) { + try { + railsRoot = root; + + // 1st: loadGameData + loadGameData(file); + + // 2nd: prepare game + convertGameData(); + + return true; + } catch (Exception e) { + log.debug("Exception during createFromFile in gameLoader ", e); + exception = e; + return false; + } + } +} diff --git a/src/main/java/net/sf/rails/util/XmlGameSaver.java b/src/main/java/net/sf/rails/util/XmlGameSaver.java new file mode 100644 index 000000000..67ed81642 --- /dev/null +++ b/src/main/java/net/sf/rails/util/XmlGameSaver.java @@ -0,0 +1,137 @@ +package net.sf.rails.util; + +import com.google.common.collect.ImmutableList; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.converters.collections.CollectionConverter; +import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; +import com.thoughtworks.xstream.converters.reflection.ReflectionConverter; +import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; +import net.sf.rails.common.Config; +import net.sf.rails.common.GameData; +import net.sf.rails.common.LocalText; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import rails.game.action.PossibleAction; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Serializable; +import java.nio.file.Files; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + + +/** + * GameLoader is responsible to load a saved Rails game + */ +public class XmlGameSaver implements IGameSaver { + + private static final Logger log = LoggerFactory.getLogger(XmlGameSaver.class); + + /** + * Version ID of the Save file header, as written in save() + */ + private static final long SAVE_FILE_HEADER_VERSION_ID = 3L; + /** + * Overall save file version ID, taking into account the version ID of the + * action package. + */ + public static final long saveFileVersionID = SAVE_FILE_HEADER_VERSION_ID * PossibleAction.serialVersionUID; + + // static data for autosave + public static final String AUTOSAVE_FOLDER = "autosave"; + public static final String AUTOSAVE_FILE = "18xx_autosave.rails"; + + // game data + private final GameIOData gameIOData = new GameIOData(); + + /** + * Creates a new game saver + * + * @param gameData of the game to save + * @param actions to save + */ + public XmlGameSaver(GameData gameData, List actions) { + gameIOData.setGameData(gameData); + gameIOData.setVersion(Config.getVersion()); + gameIOData.setDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); + gameIOData.setActions(actions); + gameIOData.setFileVersionID(saveFileVersionID); + } + + /** + * Creates a new game saver based on a gameLoader + * + * @param gameLoader to use + */ + public XmlGameSaver(GameLoader gameLoader) { + this(gameLoader.getRoot().getGameData(), gameLoader.getActions()); + } + + /** + * Stores the game to a file + * + * @param file to save game to + */ + public void saveGame(File file) throws IOException { + log.info("Saving to {}", file.getAbsoluteFile()); + + final XStream xStream = new XStream(); + + try (OutputStream outputStream = Files.newOutputStream(file.toPath())) { + xStream.toXML(gameIOData, outputStream); + } + + log.debug("File save successful"); + } + + /** + * stores game to autosave file + * + * @throws IOException + */ + public void autoSave() throws IOException { + File directory = SystemOS.get().getConfigurationFolder(AUTOSAVE_FOLDER, true); + String fileName = AUTOSAVE_FILE; + + // create temporary new save file + File tempFile = new File(directory, fileName + ".tmp"); + saveGame(tempFile); + log.debug("Created temporary recovery file, path = {}", tempFile.getPath()); + + // rename the temp file to the recover file + File recoveryFile = new File(directory, fileName); + log.debug("Potential recovery at {}", recoveryFile.getPath()); + // check if previous save file exists + boolean renameResult; + if (recoveryFile.exists()) { + log.debug("Recovery file exists"); + File backupFile = new File(directory, fileName + ".bak"); + //delete backup file if existing + if (backupFile.exists()) { + if (!backupFile.delete()) { + log.warn("Unable to delete file {}", backupFile); + } + } + //old recovery file becomes new backup file + if (!recoveryFile.renameTo(backupFile)) { + log.warn("Unable to rename recovery file {}", recoveryFile); + } else { + log.debug("Recovery file renamed to {}", backupFile.getPath()); + } + //temp file becomes new recoveryFile + renameResult = tempFile.renameTo(recoveryFile); + } else { + log.debug("Recovery file does not exist"); + renameResult = tempFile.renameTo(recoveryFile); + } + + if (!renameResult) { + String message = LocalText.getText("RecoveryRenameFailed"); + throw new IOException(message); + } + log.debug("Renamed to recovery file, path = {}", recoveryFile.getPath()); + } +} diff --git a/src/main/java/rails/game/action/BuyBonusToken.java b/src/main/java/rails/game/action/BuyBonusToken.java index d98b80c78..da347a719 100644 --- a/src/main/java/rails/game/action/BuyBonusToken.java +++ b/src/main/java/rails/game/action/BuyBonusToken.java @@ -6,9 +6,11 @@ import com.google.common.base.Objects; import net.sf.rails.game.PrivateCompany; +import net.sf.rails.game.RailsRoot; import net.sf.rails.game.special.SellBonusToken; import net.sf.rails.game.special.SpecialProperty; import net.sf.rails.game.state.Owner; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.RailsObjects; /** @@ -123,6 +125,24 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (in instanceof GameLoader.RailsObjectInputStream) { + privateCompany = getCompanyManager().getPrivateCompany(privateCompanyName); + if (sellerName.equalsIgnoreCase("Bank")) { + // TODO: Assume that it is the pool, not the ipo + seller = getRoot().getBank().getPool(); + } else { + seller = getCompanyManager().getPublicCompany(sellerName); + } + if (specialPropertyId > 0) { + specialProperty = (SellBonusToken) SpecialProperty.getByUniqueId(getRoot(), specialPropertyId); + } + } + } + + @Override + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + privateCompany = getCompanyManager().getPrivateCompany(privateCompanyName); if (sellerName.equalsIgnoreCase("Bank")) { // TODO: Assume that it is the pool, not the ipo @@ -131,7 +151,7 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE seller = getCompanyManager().getPublicCompany(sellerName); } if (specialPropertyId > 0) { - specialProperty = (SellBonusToken) SpecialProperty.getByUniqueId(getRoot() ,specialPropertyId); + specialProperty = (SellBonusToken) SpecialProperty.getByUniqueId(getRoot(), specialPropertyId); } } diff --git a/src/main/java/rails/game/action/BuyCertificate.java b/src/main/java/rails/game/action/BuyCertificate.java index ecf1ae762..9b5116fe8 100644 --- a/src/main/java/rails/game/action/BuyCertificate.java +++ b/src/main/java/rails/game/action/BuyCertificate.java @@ -187,22 +187,49 @@ public String toString() { } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - // Custom reading for backwards compatibility - ObjectInputStream.GetField fields = in.readFields(); - - certUniqueId = (String) fields.get("certUniqueId", null); - companyName = (String) fields.get("companyName", null); - fromName = (String) fields.get("fromName", fromName); - price = fields.get("price", price); - maximumNumber = fields.get("maximumNumber", maximumNumber); - sharePerCert = fields.get("sharePerCert", -1); - president = fields.get("president", false); + if (in instanceof GameLoader.RailsObjectInputStream) { + // Custom reading for backwards compatibility + ObjectInputStream.GetField fields = in.readFields(); + + certUniqueId = (String) fields.get("certUniqueId", null); + companyName = (String) fields.get("companyName", null); + fromName = (String) fields.get("fromName", fromName); + price = fields.get("price", price); + maximumNumber = fields.get("maximumNumber", maximumNumber); + sharePerCert = fields.get("sharePerCert", -1); + president = fields.get("president", false); + + numberBought = fields.get("numberBought", numberBought); + + /* Check for aliases (old company names) */ + CompanyManager companyManager = root.getCompanyManager(); + companyName = companyManager.checkAlias(companyName); + + if (certUniqueId != null) { + // Old style + certUniqueId = companyManager.checkAliasInCertId(certUniqueId); + certificate = getRoot().getCertificateManager().getCertificate(certUniqueId); + from = root.getPortfolioManager().getPortfolioByName(fromName); + company = certificate.getCompany(); + companyName = company.getId(); + sharePerCert = certificate.getShare(); + } else if (companyName != null) { + // New style (since Rails.1.3.1) + company = root.getCompanyManager().getPublicCompany(companyName); + from = root.getPortfolioManager().getPortfolioByUniqueName(fromName); + // We don't need the certificate anymore. + } + } else { + in.defaultReadObject(); + } + } - numberBought = fields.get("numberBought", numberBought); + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); /* Check for aliases (old company names) */ CompanyManager companyManager = root.getCompanyManager(); - companyName = companyManager.checkAlias (companyName); + companyName = companyManager.checkAlias(companyName); if (certUniqueId != null) { // Old style @@ -218,6 +245,5 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE from = root.getPortfolioManager().getPortfolioByUniqueName(fromName); // We don't need the certificate anymore. } - } - + } } diff --git a/src/main/java/rails/game/action/BuyPrivate.java b/src/main/java/rails/game/action/BuyPrivate.java index 9aaf5fd46..babcf8439 100644 --- a/src/main/java/rails/game/action/BuyPrivate.java +++ b/src/main/java/rails/game/action/BuyPrivate.java @@ -6,6 +6,8 @@ import com.google.common.base.Objects; import net.sf.rails.game.PrivateCompany; +import net.sf.rails.game.RailsRoot; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.RailsObjects; /** @@ -98,6 +100,14 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (in instanceof GameLoader.RailsObjectInputStream) { + privateCompany = getCompanyManager().getPrivateCompany(privateCompanyName); + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + privateCompany = getCompanyManager().getPrivateCompany(privateCompanyName); } diff --git a/src/main/java/rails/game/action/BuyTrain.java b/src/main/java/rails/game/action/BuyTrain.java index 17273b0c1..c2bad0408 100644 --- a/src/main/java/rails/game/action/BuyTrain.java +++ b/src/main/java/rails/game/action/BuyTrain.java @@ -5,13 +5,11 @@ import java.util.HashSet; import java.util.Set; -import net.sf.rails.game.CompanyManager; -import net.sf.rails.game.Train; -import net.sf.rails.game.TrainManager; -import net.sf.rails.game.TrainType; +import net.sf.rails.game.*; import net.sf.rails.game.special.SpecialProperty; import net.sf.rails.game.special.SpecialTrainBuy; import net.sf.rails.game.state.Owner; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.RailsObjects; import net.sf.rails.util.Util; @@ -325,28 +323,74 @@ public String toString() { /** Deserialize */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - // TEMPORARY Custom reading for backwards compatibility - ObjectInputStream.GetField fields = in.readFields(); - trainUniqueId = (String) fields.get("trainUniqueId", trainUniqueId); - typeName = (String) fields.get("typeName", null); - fromName = (String) fields.get("fromName", fromName); - fixedCost = fields.get("fixedCost", fixedCost); - trainsForExchangeUniqueIds = (String[]) fields.get("trainsForExchangeUniqueIds", trainsForExchangeUniqueIds); - forcedBuyIfNoRoute = fields.get("forcedBuyIfNoRoute", forcedBuyIfNoRoute); - forcedBuyIfHasRoute = fields.get("forcedBuyIfHasRoute", forcedBuyIfHasRoute); - presidentMustAddCash = fields.get("presidentMustAddCash", presidentMustAddCash); - presidentMayAddCash = fields.get("presidentMayAddCash", presidentMayAddCash); - presidentCashToAdd = fields.get("presidentCashToAdd", presidentCashToAdd); - specialPropertyId = fields.get("specialPropertyId", specialPropertyId); - pricePaid = fields.get("pricePaid", pricePaid); - addedCash = fields.get("addedCash", addedCash); - exchangedTrainUniqueId = (String) fields.get("exchangedTrainUniqueId", exchangedTrainUniqueId); - extraMessage = (String) fields.get("extraMessage", extraMessage); + if (in instanceof GameLoader.RailsObjectInputStream) { + // TEMPORARY Custom reading for backwards compatibility + ObjectInputStream.GetField fields = in.readFields(); + trainUniqueId = (String) fields.get("trainUniqueId", trainUniqueId); + typeName = (String) fields.get("typeName", null); + fromName = (String) fields.get("fromName", fromName); + fixedCost = fields.get("fixedCost", fixedCost); + trainsForExchangeUniqueIds = (String[]) fields.get("trainsForExchangeUniqueIds", trainsForExchangeUniqueIds); + forcedBuyIfNoRoute = fields.get("forcedBuyIfNoRoute", forcedBuyIfNoRoute); + forcedBuyIfHasRoute = fields.get("forcedBuyIfHasRoute", forcedBuyIfHasRoute); + presidentMustAddCash = fields.get("presidentMustAddCash", presidentMustAddCash); + presidentMayAddCash = fields.get("presidentMayAddCash", presidentMayAddCash); + presidentCashToAdd = fields.get("presidentCashToAdd", presidentCashToAdd); + specialPropertyId = fields.get("specialPropertyId", specialPropertyId); + pricePaid = fields.get("pricePaid", pricePaid); + addedCash = fields.get("addedCash", addedCash); + exchangedTrainUniqueId = (String) fields.get("exchangedTrainUniqueId", exchangedTrainUniqueId); + extraMessage = (String) fields.get("extraMessage", extraMessage); + + TrainManager trainManager = root.getTrainManager(); + CompanyManager companyManager = root.getCompanyManager(); + + fromName = companyManager.checkAlias(fromName); + + train = trainManager.getTrainByUniqueId(trainUniqueId); + // Note: the 2nd etc. copy of an unlimited quantity train will become null this way. + // Set getTrain() for how this is fixed. + if (typeName == null) { + if (train == null) { + // Kludge to cover not yet cloned unlimited trains + typeName = trainUniqueId.split("_")[0]; + type = trainManager.getTrainTypeByName(typeName); + } else { + type = train.getType(); + typeName = type.getName(); + } + } else { + type = trainManager.getTrainTypeByName(typeName); + } + + // TODO: This has to be replaced by a new mechanism for owners at some time + from = root.getPortfolioManager().getPortfolioByName(fromName).getParent(); + if (trainsForExchangeUniqueIds != null && trainsForExchangeUniqueIds.length > 0) { + trainsForExchange = new HashSet<>(); + for (String trainsForExchangeUniqueId : trainsForExchangeUniqueIds) { + trainsForExchange.add(trainManager.getTrainByUniqueId(trainsForExchangeUniqueId)); + } + } + + if (specialPropertyId > 0) { + specialProperty = (SpecialTrainBuy) SpecialProperty.getByUniqueId(root, specialPropertyId); + } + + if (Util.hasValue(exchangedTrainUniqueId)) { + exchangedTrain = trainManager.getTrainByUniqueId(exchangedTrainUniqueId); + } + } else { + in.defaultReadObject(); + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); TrainManager trainManager = root.getTrainManager(); CompanyManager companyManager = root.getCompanyManager(); - fromName = companyManager.checkAlias (fromName); + fromName = companyManager.checkAlias(fromName); train = trainManager.getTrainByUniqueId(trainUniqueId); // Note: the 2nd etc. copy of an unlimited quantity train will become null this way. @@ -368,7 +412,7 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE from = root.getPortfolioManager().getPortfolioByName(fromName).getParent(); if (trainsForExchangeUniqueIds != null && trainsForExchangeUniqueIds.length > 0) { trainsForExchange = new HashSet<>(); - for ( String trainsForExchangeUniqueId : trainsForExchangeUniqueIds ) { + for (String trainsForExchangeUniqueId : trainsForExchangeUniqueIds) { trainsForExchange.add(trainManager.getTrainByUniqueId(trainsForExchangeUniqueId)); } } diff --git a/src/main/java/rails/game/action/DiscardTrain.java b/src/main/java/rails/game/action/DiscardTrain.java index 6a1ecbe84..9acde5b5d 100644 --- a/src/main/java/rails/game/action/DiscardTrain.java +++ b/src/main/java/rails/game/action/DiscardTrain.java @@ -119,15 +119,34 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (in instanceof GameLoader.RailsObjectInputStream) { + TrainManager trainManager = root.getTrainManager(); + + if (discardedTrainUniqueId != null) { + discardedTrain = trainManager.getTrainByUniqueId(discardedTrainUniqueId); + } + + ownedTrains = new HashSet<>(); + if (ownedTrainsUniqueIds != null && ownedTrainsUniqueIds.length > 0) { + for (String ownedTrainsUniqueId : ownedTrainsUniqueIds) { + ownedTrains.add(trainManager.getTrainByUniqueId(ownedTrainsUniqueId)); + } + } + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + TrainManager trainManager = root.getTrainManager(); - if ( discardedTrainUniqueId != null ) { + if (discardedTrainUniqueId != null) { discardedTrain = trainManager.getTrainByUniqueId(discardedTrainUniqueId); } ownedTrains = new HashSet<>(); - if ( ownedTrainsUniqueIds != null && ownedTrainsUniqueIds.length > 0 ) { - for ( String ownedTrainsUniqueId : ownedTrainsUniqueIds ) { + if (ownedTrainsUniqueIds != null && ownedTrainsUniqueIds.length > 0) { + for (String ownedTrainsUniqueId : ownedTrainsUniqueIds) { ownedTrains.add(trainManager.getTrainByUniqueId(ownedTrainsUniqueId)); } } diff --git a/src/main/java/rails/game/action/FoldIntoNational.java b/src/main/java/rails/game/action/FoldIntoNational.java index b8effca52..e5da24d3b 100644 --- a/src/main/java/rails/game/action/FoldIntoNational.java +++ b/src/main/java/rails/game/action/FoldIntoNational.java @@ -9,6 +9,7 @@ import java.util.Arrays; import java.util.List; +import net.sf.rails.util.GameLoader; import org.jetbrains.annotations.NotNull; import net.sf.rails.game.Company; @@ -113,6 +114,32 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (in instanceof GameLoader.RailsObjectInputStream) { + Company company; + CompanyManager cmgr = getCompanyManager(); + + foldableCompanies = new ArrayList<>(); + if (foldableCompanyNames != null) { + for (String name : foldableCompanyNames.split(",")) { + company = cmgr.getPublicCompany(name); + if (company == null) company = cmgr.getPrivateCompany(name); + if (company != null) foldableCompanies.add(company); + } + } + if (Util.hasValue(foldedCompanyNames)) { + foldedCompanies = new ArrayList<>(); + for (String name : foldedCompanyNames.split(",")) { + company = cmgr.getPublicCompany(name); + if (company == null) company = cmgr.getPrivateCompany(name); + if (company != null) foldedCompanies.add(company); + } + } + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + Company company; CompanyManager cmgr = getCompanyManager(); diff --git a/src/main/java/rails/game/action/GameAction.java b/src/main/java/rails/game/action/GameAction.java index ce472b475..a113006a6 100644 --- a/src/main/java/rails/game/action/GameAction.java +++ b/src/main/java/rails/game/action/GameAction.java @@ -15,7 +15,7 @@ public class GameAction extends PossibleAction { private static final long serialVersionUID = 1L; - public static enum Mode { SAVE, LOAD, UNDO, FORCED_UNDO, REDO, EXPORT, RELOAD, NEW } + public static enum Mode { XML_SAVE, SAVE, LOAD, UNDO, FORCED_UNDO, REDO, EXPORT, RELOAD, NEW } // Server-side settings protected Mode mode = null; diff --git a/src/main/java/rails/game/action/LayBaseToken.java b/src/main/java/rails/game/action/LayBaseToken.java index 55a273e87..1147fab7f 100644 --- a/src/main/java/rails/game/action/LayBaseToken.java +++ b/src/main/java/rails/game/action/LayBaseToken.java @@ -10,6 +10,7 @@ import net.sf.rails.game.*; import net.sf.rails.game.special.SpecialProperty; import net.sf.rails.game.special.SpecialBaseTokenLay; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.RailsObjects; import net.sf.rails.util.Util; @@ -171,6 +172,27 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (in instanceof GameLoader.RailsObjectInputStream) { + MapManager mmgr = getRoot().getMapManager(); + if (Util.hasValue(locationNames)) { + locations = new ArrayList<>(); + for (String hexName : locationNames.split(",")) { + locations.add(mmgr.getHex(hexName)); + } + } + + if (specialPropertyId > 0) { + specialProperty = SpecialProperty.getByUniqueId(getRoot(), specialPropertyId); + } + if (chosenHexName != null && chosenHexName.length() > 0) { + chosenHex = mmgr.getHex(chosenHexName); + } + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + MapManager mmgr = getRoot().getMapManager(); if (Util.hasValue(locationNames)) { locations = new ArrayList<>(); @@ -186,5 +208,4 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE chosenHex = mmgr.getHex(chosenHexName); } } - } diff --git a/src/main/java/rails/game/action/LayBonusToken.java b/src/main/java/rails/game/action/LayBonusToken.java index c20935698..e73bb206e 100644 --- a/src/main/java/rails/game/action/LayBonusToken.java +++ b/src/main/java/rails/game/action/LayBonusToken.java @@ -14,6 +14,7 @@ import net.sf.rails.game.Token; import net.sf.rails.game.special.SpecialBonusTokenLay; import net.sf.rails.game.special.SpecialProperty; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.Util; /** @@ -84,6 +85,30 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (in instanceof GameLoader.RailsObjectInputStream) { + MapManager mmgr = getRoot().getMapManager(); + if (Util.hasValue(locationNames)) { + locations = new ArrayList<>(); + for (String hexName : locationNames.split(",")) { + locations.add(mmgr.getHex(hexName)); + } + } + + if (tokenId != null) { + token = Token.getByUniqueId(getRoot(), BonusToken.class, tokenId); + } + if (specialPropertyId > 0) { + specialProperty = SpecialProperty.getByUniqueId(getRoot(), specialPropertyId); + } + if (chosenHexName != null && chosenHexName.length() > 0) { + chosenHex = mmgr.getHex(chosenHexName); + } + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + MapManager mmgr = getRoot().getMapManager(); if (Util.hasValue(locationNames)) { locations = new ArrayList<>(); diff --git a/src/main/java/rails/game/action/LayTile.java b/src/main/java/rails/game/action/LayTile.java index a30ecd88f..8bdb4dd33 100644 --- a/src/main/java/rails/game/action/LayTile.java +++ b/src/main/java/rails/game/action/LayTile.java @@ -18,6 +18,7 @@ import net.sf.rails.game.TileManager; import net.sf.rails.game.special.SpecialProperty; import net.sf.rails.game.special.SpecialTileLay; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.RailsObjects; import net.sf.rails.util.Util; @@ -299,25 +300,73 @@ public String toString() { /** Deserialize */ @SuppressWarnings("unchecked") private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - // Custom reading for backwards compatibility - ObjectInputStream.GetField fields = in.readFields(); + if (in instanceof GameLoader.RailsObjectInputStream) { + // Custom reading for backwards compatibility + ObjectInputStream.GetField fields = in.readFields(); + + locationNames = (String) fields.get("locationNames", locationNames); + tileColours = (Map) fields.get("tileColours", tileColours); + // FIXME: Rewrite this with Rails1.x version flag + tileIds = (int[]) fields.get("tileIds", tileIds); + sTileIds = (String[]) fields.get("tileIds", sTileIds); + + specialPropertyId = fields.get("specialPropertyId", specialPropertyId); + // FIXME: Rewrite this with Rails1.x version flag + laidTileId = fields.get("laidTileId", laidTileId); + sLaidTileId = (String) fields.get("sLaidTileId", sLaidTileId); + + chosenHexName = (String) fields.get("chosenHexName", chosenHexName); + orientation = fields.get("orientation", orientation); + relayBaseTokens = fields.get("relayBaseTokens", relayBaseTokens); + relaidBaseTokens = (Map) fields.get("relaidBaseTokens", relaidBaseTokens); + relaidBaseTokensString = (String) fields.get("relaidBaseTokensString", relaidBaseTokensString); + + MapManager mmgr = getRoot().getMapManager(); + TileManager tmgr = getRoot().getTileManager(); + + if (Util.hasValue(locationNames)) { + locations = new ArrayList<>(); + for (String hexName : locationNames.split(",")) { + locations.add(mmgr.getHex(hexName)); + } + } - locationNames = (String) fields.get("locationNames", locationNames); - tileColours = (Map) fields.get("tileColours", tileColours); - // FIXME: Rewrite this with Rails1.x version flag - tileIds = (int[]) fields.get("tileIds", tileIds); - sTileIds = (String[]) fields.get("tileIds", sTileIds); + // FIXME: Rewrite this with Rails1.x version flag + if (tileIds != null && tileIds.length > 0) { + tiles = new ArrayList<>(); + for (int tileNb : tileIds) { + tiles.add(tmgr.getTile(String.valueOf(tileNb))); + } + } - specialPropertyId = fields.get("specialPropertyId", specialPropertyId); - // FIXME: Rewrite this with Rails1.x version flag - laidTileId = fields.get("laidTileId", laidTileId); - sLaidTileId = (String)fields.get("sLaidTileId", sLaidTileId); + if (sTileIds != null && sTileIds.length > 0) { + tiles = new ArrayList<>(); + for (String tileId : sTileIds) { + tiles.add(tmgr.getTile(tileId)); + } + } + + if (specialPropertyId > 0) { + specialProperty = (SpecialTileLay) SpecialProperty.getByUniqueId(getRoot(), specialPropertyId); + } + // FIXME: Rewrite this with Rails1.x version flag + if (laidTileId != 0) { + sLaidTileId = String.valueOf(laidTileId); + } + if (sLaidTileId != null) { + laidTile = tmgr.getTile(sLaidTileId); + } - chosenHexName = (String) fields.get("chosenHexName", chosenHexName); - orientation = fields.get("orientation", orientation); - relayBaseTokens = fields.get("relayBaseTokens", relayBaseTokens); - relaidBaseTokens = (Map)fields.get("relaidBaseTokens", relaidBaseTokens); - relaidBaseTokensString = (String) fields.get("relaidBaseTokensString", relaidBaseTokensString); + if (chosenHexName != null && chosenHexName.length() > 0) { + chosenHex = mmgr.getHex(chosenHexName); + } + } else { + in.defaultReadObject(); + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); MapManager mmgr = getRoot().getMapManager(); TileManager tmgr = getRoot().getTileManager(); @@ -332,14 +381,14 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE // FIXME: Rewrite this with Rails1.x version flag if (tileIds != null && tileIds.length > 0) { tiles = new ArrayList<>(); - for (int tileNb:tileIds) { + for (int tileNb : tileIds) { tiles.add(tmgr.getTile(String.valueOf(tileNb))); } } if (sTileIds != null && sTileIds.length > 0) { tiles = new ArrayList<>(); - for (String tileId:sTileIds) { + for (String tileId : sTileIds) { tiles.add(tmgr.getTile(tileId)); } } @@ -358,7 +407,6 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE if (chosenHexName != null && chosenHexName.length() > 0) { chosenHex = mmgr.getHex(chosenHexName); } - } private void buildLocationNameString() { diff --git a/src/main/java/rails/game/action/MergeCompanies.java b/src/main/java/rails/game/action/MergeCompanies.java index 1a372230e..00c2505e1 100644 --- a/src/main/java/rails/game/action/MergeCompanies.java +++ b/src/main/java/rails/game/action/MergeCompanies.java @@ -7,6 +7,7 @@ import java.util.Collections; import java.util.List; +import net.sf.rails.util.GameLoader; import org.jetbrains.annotations.NotNull; import com.google.common.base.Objects; @@ -143,13 +144,37 @@ public String toString() { @SuppressWarnings("unchecked") private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - // Custom reading for backwards compatibility - ObjectInputStream.GetField fields = in.readFields(); - mergingCompanyName = (String) fields.get("mergingCompanyName", mergingCompanyName); - targetCompanyNames = (String) fields.get("targetCompanyNames", targetCompanyNames); - canReplaceToken = (List) fields.get("canReplaceToken", canReplaceToken); - selectedTargetCompanyName = (String) fields.get("selectedTargetCompanyName", selectedTargetCompanyName); - replaceToken = fields.get("replaceToken", replaceToken); + if (in instanceof GameLoader.RailsObjectInputStream) { + // Custom reading for backwards compatibility + ObjectInputStream.GetField fields = in.readFields(); + mergingCompanyName = (String) fields.get("mergingCompanyName", mergingCompanyName); + targetCompanyNames = (String) fields.get("targetCompanyNames", targetCompanyNames); + canReplaceToken = (List) fields.get("canReplaceToken", canReplaceToken); + selectedTargetCompanyName = (String) fields.get("selectedTargetCompanyName", selectedTargetCompanyName); + replaceToken = fields.get("replaceToken", replaceToken); + + CompanyManager cmgr = getCompanyManager(); + mergingCompany = cmgr.getPublicCompany(mergingCompanyName); + + targetCompanies = new ArrayList<>(); + for (String name : targetCompanyNames.split(",")) { + if (name.equals("null")) { + targetCompanies.add(null); + } else { + targetCompanies.add(cmgr.getPublicCompany(name)); + } + } + + if (selectedTargetCompanyName != null && !selectedTargetCompanyName.equals("null")) { + selectedTargetCompany = cmgr.getPublicCompany(selectedTargetCompanyName); + } + } else { + in.defaultReadObject(); + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); CompanyManager cmgr = getCompanyManager(); mergingCompany = cmgr.getPublicCompany(mergingCompanyName); diff --git a/src/main/java/rails/game/action/NullAction.java b/src/main/java/rails/game/action/NullAction.java index cee3c8979..19671c58a 100644 --- a/src/main/java/rails/game/action/NullAction.java +++ b/src/main/java/rails/game/action/NullAction.java @@ -4,18 +4,19 @@ import java.io.ObjectInputStream; import net.sf.rails.game.RailsRoot; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.RailsObjects; import com.google.common.base.Objects; /** - * * Rails 2.0: Updated equals and toString methods */ public class NullAction extends PossibleAction { private static final long serialVersionUID = 2L; - public enum Mode { DONE, PASS, SKIP, AUTOPASS, START_GAME } + + public enum Mode {DONE, PASS, SKIP, AUTOPASS, START_GAME} // optional label that is returned on toString instead of the standard labels defined below private String optionalLabel = null; @@ -34,7 +35,9 @@ public Mode getMode() { return mode_enum; } - /** returns the NullAction itself */ + /** + * returns the NullAction itself + */ public NullAction setLabel(String label) { this.optionalLabel = label; return this; @@ -48,28 +51,36 @@ protected boolean equalsAs(PossibleAction pa, boolean asOption) { if (!super.equalsAs(pa, asOption)) return false; // check asOption attributes - NullAction action = (NullAction)pa; + NullAction action = (NullAction) pa; return Objects.equal(this.mode, action.mode) && Objects.equal(this.optionalLabel, action.optionalLabel) - ; + ; // no asAction attributes to be checked } - @Override + @Override public String toString() { - return super.toString() + - RailsObjects.stringHelper(this) - .addToString("mode", mode_enum) - .addToString("optionalLabel", optionalLabel) - .toString() - ; + return super.toString() + + RailsObjects.stringHelper(this) + .addToString("mode", mode_enum) + .addToString("optionalLabel", optionalLabel) + .toString() + ; } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); - // required since Rails 2.0 - mode_enum = Mode.values()[mode]; - } + if (in instanceof GameLoader.RailsObjectInputStream) { + // required since Rails 2.0 + mode_enum = Mode.values()[mode]; + } + } + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + + // required since Rails 2.0 + mode_enum = Mode.values()[mode]; + } } diff --git a/src/main/java/rails/game/action/PossibleAction.java b/src/main/java/rails/game/action/PossibleAction.java index 7009420c8..d376b19aa 100644 --- a/src/main/java/rails/game/action/PossibleAction.java +++ b/src/main/java/rails/game/action/PossibleAction.java @@ -24,7 +24,7 @@ * PossibleAction is the superclass of all classes that describe an allowed user * action (such as laying a tile or dropping a token on a specific hex, buying a * train etc.). - * + *

* Rails 2.0: Added updated equals and toString methods */ @@ -48,7 +48,7 @@ public abstract class PossibleAction implements ChangeAction, Serializable { // TODO: Replace this by a constructor argument for the player public PossibleAction(Activity activity) { - if ( activity == null ) { + if (activity == null) { return; } root = activity.getRoot(); @@ -57,7 +57,7 @@ public PossibleAction(Activity activity) { } public PossibleAction(RailsRoot root) { - if ( root == null ) { + if (root == null) { log.debug("missing root", new Exception()); return; } @@ -65,6 +65,10 @@ public PossibleAction(RailsRoot root) { setPlayer(); } + protected PossibleAction() { + // do nothing + } + public void setPlayer() { player = root.getPlayerManager().getCurrentPlayer(); if (player != null) { @@ -114,8 +118,8 @@ protected boolean equalsAs(PossibleAction pa, boolean asOption) { // check asOption attributes boolean options = Objects.equal(this.player, pa.player) - || pa instanceof NullAction // TODO: Old save files are sometimes wrong to assign Null Actions - ; + || pa instanceof NullAction // TODO: Old save files are sometimes wrong to assign Null Actions + ; // finish if asOptions check if (asOption) return options; @@ -135,10 +139,11 @@ protected boolean equalsAs(PossibleAction pa, boolean asOption) { * the PossibleAction does not fully restrict choices to valid values only * (such as the blanket LayTile that does no restrict the hex to lay a tile on, * or the SetDividend that will accept any revenue value). + * * @param pa Another PossibleAction to compare with. * @return True if the compared PossibleAction object has equal choice options. */ - public final boolean equalsAsOption (PossibleAction pa) { + public final boolean equalsAsOption(PossibleAction pa) { return equalsAs(pa, true); } @@ -149,10 +154,11 @@ public final boolean equalsAsOption (PossibleAction pa) { *

This method is used by the server (engine) to check if two action * objects represent the same actual action, as is done when reloading a saved file * (i.e. loading a later stage of the same game). + * * @param pa Another PossibleAction to compare with. * @return True if the compared PossibleAction object has equal selected action values. */ - public final boolean equalsAsAction (PossibleAction pa) { + public final boolean equalsAsAction(PossibleAction pa) { return equalsAs(pa, false); } @@ -164,7 +170,7 @@ protected GameManager getGameManager() { return root.getGameManager(); } - protected CompanyManager getCompanyManager () { + protected CompanyManager getCompanyManager() { return root.getCompanyManager(); } @@ -179,7 +185,9 @@ public boolean isCorrection() { return false; } - /** Default version of an Menu item text. To be overridden where useful. */ + /** + * Default version of an Menu item text. To be overridden where useful. + */ public String toMenu() { return toString(); } @@ -198,8 +206,20 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); - // inject RailsRoot for use by all subclasses during their own deserializing - root = ((RailsObjectInputStream) in).getRoot(); + if (in instanceof RailsObjectInputStream) { + // inject RailsRoot for use by all subclasses during their own deserializing + this.root = ((RailsObjectInputStream) in).getRoot(); + + if (playerName != null) { + player = root.getPlayerManager().getPlayerByName(playerName); + } else { + player = root.getPlayerManager().getPlayerByIndex(playerIndex); + } + } + } + + public void applyRailsRoot(RailsRoot root) { + this.root = root; if (playerName != null) { player = root.getPlayerManager().getPlayerByName(playerName); @@ -207,5 +227,4 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE player = root.getPlayerManager().getPlayerByIndex(playerIndex); } } - } diff --git a/src/main/java/rails/game/action/PossibleActions.java b/src/main/java/rails/game/action/PossibleActions.java index bd8ba0890..f175ef58a 100644 --- a/src/main/java/rails/game/action/PossibleActions.java +++ b/src/main/java/rails/game/action/PossibleActions.java @@ -89,7 +89,7 @@ public boolean validate(PossibleAction checkedAction) { // Some actions are always allowed if (checkedAction instanceof GameAction - && EnumSet.of(GameAction.Mode.SAVE, GameAction.Mode.RELOAD, GameAction.Mode.EXPORT).contains( + && EnumSet.of(GameAction.Mode.XML_SAVE, GameAction.Mode.SAVE, GameAction.Mode.RELOAD, GameAction.Mode.EXPORT).contains( ((GameAction)checkedAction).getMode() )) { return true; } diff --git a/src/main/java/rails/game/action/PossibleORAction.java b/src/main/java/rails/game/action/PossibleORAction.java index 23850790a..52f8a1a75 100644 --- a/src/main/java/rails/game/action/PossibleORAction.java +++ b/src/main/java/rails/game/action/PossibleORAction.java @@ -9,6 +9,7 @@ import net.sf.rails.game.PublicCompany; import net.sf.rails.game.RailsRoot; import net.sf.rails.game.round.RoundFacade; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.RailsObjects; import net.sf.rails.util.Util; @@ -86,7 +87,17 @@ public String toString () { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); - if (Util.hasValue(companyName)) + if (in instanceof GameLoader.RailsObjectInputStream) { + if (Util.hasValue(companyName)) + company = getCompanyManager().getPublicCompany(companyName); + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + + if (Util.hasValue(companyName)) { company = getCompanyManager().getPublicCompany(companyName); + } } } diff --git a/src/main/java/rails/game/action/ReachDestinations.java b/src/main/java/rails/game/action/ReachDestinations.java index cc85252bd..2e648dd85 100644 --- a/src/main/java/rails/game/action/ReachDestinations.java +++ b/src/main/java/rails/game/action/ReachDestinations.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.List; +import net.sf.rails.util.GameLoader; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; @@ -96,12 +97,38 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (in instanceof GameLoader.RailsObjectInputStream) { + CompanyManager cmgr = getCompanyManager(); + + possibleCompanies = new ArrayList<>(); + if (Util.hasValue(possibleCompanyNames)) { + for (String cname : possibleCompanyNames.split(",")) { + if (StringUtils.isNotBlank(cname)) { + possibleCompanies.add(cmgr.getPublicCompany(cname)); + } + } + } + + if (Util.hasValue(reachedCompanyNames)) { + reachedCompanies = new ArrayList<>(); + for (String cname : reachedCompanyNames.split(",")) { + if (StringUtils.isNotBlank(cname)) { + reachedCompanies.add(cmgr.getPublicCompany(cname)); + } + } + } + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + CompanyManager cmgr = getCompanyManager(); possibleCompanies = new ArrayList<>(); if (Util.hasValue(possibleCompanyNames)) { for (String cname : possibleCompanyNames.split(",")) { - if ( StringUtils.isNotBlank(cname) ) { + if (StringUtils.isNotBlank(cname)) { possibleCompanies.add(cmgr.getPublicCompany(cname)); } } @@ -110,7 +137,7 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE if (Util.hasValue(reachedCompanyNames)) { reachedCompanies = new ArrayList<>(); for (String cname : reachedCompanyNames.split(",")) { - if ( StringUtils.isNotBlank(cname) ) { + if (StringUtils.isNotBlank(cname)) { reachedCompanies.add(cmgr.getPublicCompany(cname)); } } diff --git a/src/main/java/rails/game/action/RepayLoans.java b/src/main/java/rails/game/action/RepayLoans.java index 19dd2585b..74fe852e8 100644 --- a/src/main/java/rails/game/action/RepayLoans.java +++ b/src/main/java/rails/game/action/RepayLoans.java @@ -6,6 +6,8 @@ import com.google.common.base.Objects; import net.sf.rails.game.PublicCompany; +import net.sf.rails.game.RailsRoot; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.RailsObjects; /** @@ -114,6 +116,14 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (in instanceof GameLoader.RailsObjectInputStream) { + company = getCompanyManager().getPublicCompany(companyName); + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + company = getCompanyManager().getPublicCompany(companyName); } diff --git a/src/main/java/rails/game/action/SellShares.java b/src/main/java/rails/game/action/SellShares.java index 7db59caf1..e268477ce 100644 --- a/src/main/java/rails/game/action/SellShares.java +++ b/src/main/java/rails/game/action/SellShares.java @@ -7,6 +7,8 @@ import net.sf.rails.game.CompanyManager; import net.sf.rails.game.PublicCompany; +import net.sf.rails.game.RailsRoot; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.RailsObjects; import net.sf.rails.util.Util; @@ -135,17 +137,30 @@ public String toString() { /** Deserialize */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - // Custom reading for backwards compatibility - ObjectInputStream.GetField fields = in.readFields(); - - companyName = (String) fields.get("companyName", null); - shareUnit = fields.get("shareUnit", shareUnit); - shareUnits = fields.get("shareUnits", shareUnits); - share = fields.get("share", share); - price = fields.get("price", price); - numberSold = fields.get("numberSold", 0); // For backwards compatibility - number = fields.get("number", numberSold); - presidentExchange = fields.get("presidentExchange", 0); + if (in instanceof GameLoader.RailsObjectInputStream) { + // Custom reading for backwards compatibility + ObjectInputStream.GetField fields = in.readFields(); + + companyName = (String) fields.get("companyName", null); + shareUnit = fields.get("shareUnit", shareUnit); + shareUnits = fields.get("shareUnits", shareUnits); + share = fields.get("share", share); + price = fields.get("price", price); + numberSold = fields.get("numberSold", 0); // For backwards compatibility + number = fields.get("number", numberSold); + presidentExchange = fields.get("presidentExchange", 0); + + CompanyManager companyManager = getCompanyManager(); + if (Util.hasValue(companyName)) + companyName = companyManager.checkAlias(companyName); + company = companyManager.getPublicCompany(companyName); + } else { + in.defaultReadObject(); + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); CompanyManager companyManager = getCompanyManager(); if (Util.hasValue(companyName)) diff --git a/src/main/java/rails/game/action/SetDividend.java b/src/main/java/rails/game/action/SetDividend.java index d51766125..3b2413477 100644 --- a/src/main/java/rails/game/action/SetDividend.java +++ b/src/main/java/rails/game/action/SetDividend.java @@ -7,6 +7,7 @@ import com.google.common.base.Objects; import net.sf.rails.game.RailsRoot; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.RailsObjects; import net.sf.rails.util.Util; @@ -233,16 +234,28 @@ public String toString() { /** Deserialize */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - // Custom deserialization for backwards compatibility - ObjectInputStream.GetField fields = in.readFields(); - presetRevenue = fields.get("presetRevenue", presetRevenue); - presetCompanyTreasuryRevenue = fields.get("presetCompanyTreasuryRevenue", presetCompanyTreasuryRevenue); - setMayUserSetRevenue(fields.get("mayUserSetRevenue", getMayUserSetRevenue())); - setAllowedRevenueAllocations((int[]) fields.get("allowedRevenueAllocations", getAllowedRevenueAllocations())); - requiredCash = fields.get("requiredCash", 0); - actualRevenue = fields.get("actualRevenue", actualRevenue); - actualCompanyTreasuryRevenue = fields.get("actualCompanyTreasuryRevenue", actualCompanyTreasuryRevenue); - revenueAllocation = fields.get("revenueAllocation", revenueAllocation); + if (in instanceof GameLoader.RailsObjectInputStream) { + // Custom deserialization for backwards compatibility + ObjectInputStream.GetField fields = in.readFields(); + presetRevenue = fields.get("presetRevenue", presetRevenue); + presetCompanyTreasuryRevenue = fields.get("presetCompanyTreasuryRevenue", presetCompanyTreasuryRevenue); + setMayUserSetRevenue(fields.get("mayUserSetRevenue", getMayUserSetRevenue())); + setAllowedRevenueAllocations((int[]) fields.get("allowedRevenueAllocations", getAllowedRevenueAllocations())); + requiredCash = fields.get("requiredCash", 0); + actualRevenue = fields.get("actualRevenue", actualRevenue); + actualCompanyTreasuryRevenue = fields.get("actualCompanyTreasuryRevenue", actualCompanyTreasuryRevenue); + revenueAllocation = fields.get("revenueAllocation", revenueAllocation); + + if (Util.hasValue(companyName)) { + company = getCompanyManager().getPublicCompany(companyName); + } + } else { + in.defaultReadObject(); + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); if (Util.hasValue(companyName)) { company = getCompanyManager().getPublicCompany(companyName); diff --git a/src/main/java/rails/game/action/StartItemAction.java b/src/main/java/rails/game/action/StartItemAction.java index b794d5efa..ad640463a 100644 --- a/src/main/java/rails/game/action/StartItemAction.java +++ b/src/main/java/rails/game/action/StartItemAction.java @@ -7,6 +7,7 @@ import net.sf.rails.game.RailsRoot; import net.sf.rails.game.StartItem; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.RailsObjects; @@ -37,6 +38,10 @@ public StartItemAction (RailsRoot root) { super (root); } + protected StartItemAction() { + super(); + } + /** * @return Returns the startItem. */ @@ -78,6 +83,18 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); - startItem = root.getCompanyManager().getStartItemById(startItemName); + if (in instanceof GameLoader.RailsObjectInputStream) { + if (root != null) { + startItem = root.getCompanyManager().getStartItemById(startItemName); + } + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + + if (root != null) { + startItem = root.getCompanyManager().getStartItemById(startItemName); + } } } diff --git a/src/main/java/rails/game/action/TakeLoans.java b/src/main/java/rails/game/action/TakeLoans.java index 80f4418d2..680170b53 100644 --- a/src/main/java/rails/game/action/TakeLoans.java +++ b/src/main/java/rails/game/action/TakeLoans.java @@ -6,6 +6,8 @@ import com.google.common.base.Objects; import net.sf.rails.game.PublicCompany; +import net.sf.rails.game.RailsRoot; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.RailsObjects; /** @@ -101,7 +103,14 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); - company = getCompanyManager().getPublicCompany(companyName); + if (in instanceof GameLoader.RailsObjectInputStream) { + company = getCompanyManager().getPublicCompany(companyName); + } } + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + + company = getCompanyManager().getPublicCompany(companyName); + } } diff --git a/src/main/java/rails/game/action/UseSpecialProperty.java b/src/main/java/rails/game/action/UseSpecialProperty.java index 9d321d0ed..15a444e8a 100644 --- a/src/main/java/rails/game/action/UseSpecialProperty.java +++ b/src/main/java/rails/game/action/UseSpecialProperty.java @@ -5,7 +5,9 @@ import com.google.common.base.Objects; +import net.sf.rails.game.RailsRoot; import net.sf.rails.game.special.SpecialProperty; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.RailsObjects; @@ -70,6 +72,16 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (in instanceof GameLoader.RailsObjectInputStream) { + if (specialPropertyId > 0) { + specialProperty = SpecialProperty.getByUniqueId(getRoot(), specialPropertyId); + } + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + if (specialPropertyId > 0) { specialProperty = SpecialProperty.getByUniqueId(getRoot(), specialPropertyId); } diff --git a/src/main/java/rails/game/correct/CashCorrectionAction.java b/src/main/java/rails/game/correct/CashCorrectionAction.java index 4dbb84eca..c31396122 100644 --- a/src/main/java/rails/game/correct/CashCorrectionAction.java +++ b/src/main/java/rails/game/correct/CashCorrectionAction.java @@ -7,6 +7,7 @@ import com.google.common.base.Objects; import net.sf.rails.game.RailsRoot; +import net.sf.rails.util.GameLoader; import rails.game.action.PossibleAction; import net.sf.rails.game.Player; import net.sf.rails.game.PublicCompany; @@ -125,6 +126,22 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (in instanceof GameLoader.RailsObjectInputStream) { + if (Util.hasValue(correctionName)) + correctionType = CorrectionType.valueOf(correctionName); + + if (Util.hasValue(cashHolderType) && Util.hasValue(cashHolderName)) { + if (cashHolderType.equals("Player")) + correctCashHolder = getGameManager().getRoot().getPlayerManager().getPlayerByName(cashHolderName); + else if (cashHolderType.equals("PublicCompany")) + correctCashHolder = getCompanyManager().getPublicCompany(cashHolderName); + } + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + if (Util.hasValue(correctionName)) correctionType = CorrectionType.valueOf(correctionName); diff --git a/src/main/java/rails/game/correct/ClosePrivate.java b/src/main/java/rails/game/correct/ClosePrivate.java index 26e6ed177..e9fe9dd10 100644 --- a/src/main/java/rails/game/correct/ClosePrivate.java +++ b/src/main/java/rails/game/correct/ClosePrivate.java @@ -5,6 +5,8 @@ import com.google.common.base.Objects; +import net.sf.rails.game.RailsRoot; +import net.sf.rails.util.GameLoader; import rails.game.action.PossibleAction; import net.sf.rails.game.PrivateCompany; import net.sf.rails.util.RailsObjects; @@ -72,7 +74,17 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); - if (Util.hasValue(privateCompanyName)) + if (in instanceof GameLoader.RailsObjectInputStream) { + if (Util.hasValue(privateCompanyName)) privateCompany = getCompanyManager().getPrivateCompany(privateCompanyName); + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + + if (Util.hasValue(privateCompanyName)) { + privateCompany = getCompanyManager().getPrivateCompany(privateCompanyName); + } } } diff --git a/src/main/java/rails/game/correct/CorrectionModeAction.java b/src/main/java/rails/game/correct/CorrectionModeAction.java index fea32421d..ba82a3311 100644 --- a/src/main/java/rails/game/correct/CorrectionModeAction.java +++ b/src/main/java/rails/game/correct/CorrectionModeAction.java @@ -78,10 +78,19 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); - if (Util.hasValue(correctionName)) + if (in instanceof GameLoader.RailsObjectInputStream) { + if (Util.hasValue(correctionName)) correctionType = CorrectionType.valueOf(correctionName); + } } + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + + if (Util.hasValue(correctionName)) { + correctionType = CorrectionType.valueOf(correctionName); + } + } // a version with enumsets: // // pre-conditions diff --git a/src/main/java/rails/game/correct/MapCorrectionAction.java b/src/main/java/rails/game/correct/MapCorrectionAction.java index c1e93d517..87933f32c 100644 --- a/src/main/java/rails/game/correct/MapCorrectionAction.java +++ b/src/main/java/rails/game/correct/MapCorrectionAction.java @@ -7,6 +7,7 @@ import com.google.common.base.Objects; import net.sf.rails.game.RailsRoot; +import net.sf.rails.util.GameLoader; import rails.game.action.PossibleAction; import rails.game.correct.MapCorrectionManager.*; import net.sf.rails.game.BaseToken; @@ -29,10 +30,14 @@ @Deprecated public class MapCorrectionAction extends CorrectionAction { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ public static final long serialVersionUID = 1L; - /** Sequence: Indicates the enrichment of the action */ + /** + * Sequence: Indicates the enrichment of the action + */ private transient ActionStep step = null; private String stepName; @@ -41,20 +46,28 @@ public class MapCorrectionAction extends CorrectionAction { /* Conditions */ - /** Location: where to lay the tile */ + /** + * Location: where to lay the tile + */ private transient MapHex location = null; private String locationCoordinates; - /** Tiles: which tile(s) to lay */ + /** + * Tiles: which tile(s) to lay + */ private transient List tiles = null; private String[] sTileIds; // FIXME: Rewrite this with Rails1.x version flag private int[] tileIds; - /** Orientation: how to lay the tile */ + /** + * Orientation: how to lay the tile + */ private int orientation; - /** RelayBaseTokens: how to relay the base tokens */ + /** + * RelayBaseTokens: how to relay the base tokens + */ private transient List tokensToRelay; //private String[]tokensToRelayOwner; private transient List stationsForRelay; @@ -124,7 +137,7 @@ void setPossibleStations(Collection possibleStations) { this.possibleStations = possibleStations; } - public int getOrientation(){ + public int getOrientation() { return orientation; } @@ -202,27 +215,64 @@ protected boolean equalsAs(PossibleAction pa, boolean asOption) { if (asOption) return true; // check asAction attributes - MapCorrectionAction action = (MapCorrectionAction)pa; + MapCorrectionAction action = (MapCorrectionAction) pa; return Objects.equal(this.location, action.location) && Objects.equal(this.tiles, action.tiles) && Objects.equal(this.orientation, action.orientation) - ; + ; } @Override - public String toString(){ + public String toString() { return super.toString() + RailsObjects.stringHelper(this) - .addToStringOnlyActed("location", location) - .addToStringOnlyActed("tiles", tiles) - .addToStringOnlyActed("orientation", orientation) - ; + .addToStringOnlyActed("location", location) + .addToStringOnlyActed("tiles", tiles) + .addToStringOnlyActed("orientation", orientation) + ; } - /** Deserialize */ + /** + * Deserialize + */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (in instanceof GameLoader.RailsObjectInputStream) { + if (Util.hasValue(correctionName)) + correctionType = CorrectionType.valueOf(correctionName); + + if (Util.hasValue(stepName)) + step = ActionStep.valueOf(stepName); + + if (Util.hasValue(nextStepName)) + nextStep = ActionStep.valueOf(nextStepName); + + MapManager mmgr = getRoot().getMapManager(); + if (Util.hasValue(locationCoordinates)) + location = mmgr.getHex(locationCoordinates); + + TileManager tmgr = getRoot().getTileManager(); + if (sTileIds != null && sTileIds.length > 0) { + tiles = new ArrayList<>(); + for (String sTileId : sTileIds) { + tiles.add(tmgr.getTile(sTileId)); + } + } + + // FIXME: Rewrite this with Rails1.x version flag + if (tileIds != null && tileIds.length > 0) { + tiles = new ArrayList<>(); + for (int tileId : tileIds) { + tiles.add(tmgr.getTile(String.valueOf(tileId))); + } + } + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + if (Util.hasValue(correctionName)) correctionType = CorrectionType.valueOf(correctionName); @@ -239,7 +289,7 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE TileManager tmgr = getRoot().getTileManager(); if (sTileIds != null && sTileIds.length > 0) { tiles = new ArrayList<>(); - for ( String sTileId : sTileIds ) { + for (String sTileId : sTileIds) { tiles.add(tmgr.getTile(sTileId)); } } @@ -247,7 +297,7 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE // FIXME: Rewrite this with Rails1.x version flag if (tileIds != null && tileIds.length > 0) { tiles = new ArrayList<>(); - for ( int tileId : tileIds ) { + for (int tileId : tileIds) { tiles.add(tmgr.getTile(String.valueOf(tileId))); } } diff --git a/src/main/java/rails/game/correct/OperatingCost.java b/src/main/java/rails/game/correct/OperatingCost.java index e1afbfc63..aacf37a33 100644 --- a/src/main/java/rails/game/correct/OperatingCost.java +++ b/src/main/java/rails/game/correct/OperatingCost.java @@ -6,6 +6,7 @@ import com.google.common.base.Objects; import net.sf.rails.game.RailsRoot; +import net.sf.rails.util.GameLoader; import rails.game.action.PossibleAction; import rails.game.action.PossibleORAction; import net.sf.rails.util.RailsObjects; @@ -117,7 +118,18 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); - if (Util.hasValue(companyName)) + if (in instanceof GameLoader.RailsObjectInputStream) { + if (Util.hasValue(companyName)) company = getCompanyManager().getPublicCompany(companyName); + } + } + + @Override + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + + if (Util.hasValue(companyName)) { + company = getCompanyManager().getPublicCompany(companyName); + } } } diff --git a/src/main/java/rails/game/specific/_1835/FoldIntoPrussian.java b/src/main/java/rails/game/specific/_1835/FoldIntoPrussian.java index 144d40901..067f80c46 100644 --- a/src/main/java/rails/game/specific/_1835/FoldIntoPrussian.java +++ b/src/main/java/rails/game/specific/_1835/FoldIntoPrussian.java @@ -6,6 +6,7 @@ import java.util.Arrays; import java.util.List; +import net.sf.rails.util.GameLoader; import org.jetbrains.annotations.NotNull; import net.sf.rails.game.RailsRoot; @@ -110,6 +111,33 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (in instanceof GameLoader.RailsObjectInputStream) { + Company company; + CompanyManager cmgr = getCompanyManager(); + + foldableCompanies = new ArrayList<>(); + if (foldableCompanyNames != null) { + for (String name : foldableCompanyNames.split(",")) { + company = cmgr.getPublicCompany(name); + if (company == null) company = cmgr.getPrivateCompany(name); + if (company != null) foldableCompanies.add(company); + } + } + if (Util.hasValue(foldedCompanyNames)) { + foldedCompanies = new ArrayList<>(); + for (String name : foldedCompanyNames.split(",")) { + company = cmgr.getPublicCompany(name); + if (company == null) company = cmgr.getPrivateCompany(name); + if (company != null) foldedCompanies.add(company); + } + } + } + } + + @Override + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + Company company; CompanyManager cmgr = getCompanyManager(); @@ -130,5 +158,4 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE } } } - } diff --git a/src/main/java/rails/game/specific/_1837/SetHomeHexLocation.java b/src/main/java/rails/game/specific/_1837/SetHomeHexLocation.java index c0833dd05..3201755fa 100644 --- a/src/main/java/rails/game/specific/_1837/SetHomeHexLocation.java +++ b/src/main/java/rails/game/specific/_1837/SetHomeHexLocation.java @@ -2,6 +2,7 @@ import com.google.common.base.Objects; import net.sf.rails.game.*; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.RailsObjects; import net.sf.rails.util.Util; import rails.game.action.PossibleAction; @@ -79,8 +80,18 @@ private String[] parseStationName (String name) { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); - if (Util.hasValue(companyName)) + if (in instanceof GameLoader.RailsObjectInputStream) { + if (Util.hasValue(companyName)) + company = getCompanyManager().getPublicCompany(companyName); + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + + if (Util.hasValue(companyName)) { company = getCompanyManager().getPublicCompany(companyName); + } } public PublicCompany getCompany() { diff --git a/src/main/java/rails/game/specific/_1880/ExchangeForCash.java b/src/main/java/rails/game/specific/_1880/ExchangeForCash.java index f1c474246..543d431f5 100644 --- a/src/main/java/rails/game/specific/_1880/ExchangeForCash.java +++ b/src/main/java/rails/game/specific/_1880/ExchangeForCash.java @@ -8,8 +8,10 @@ import com.google.common.collect.ImmutableMap; import net.sf.rails.game.PrivateCompany; +import net.sf.rails.game.RailsRoot; import net.sf.rails.game.TrainType; import net.sf.rails.game.state.Owner; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.RailsObjects; import net.sf.rails.util.Util; import rails.game.action.PossibleAction; @@ -108,6 +110,17 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (in instanceof GameLoader.RailsObjectInputStream) { + if (Util.hasValue(ownerName)) { + owner = getRoot().getPlayerManager().getPlayerByName(ownerName); + } + } + } + + @Override + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + if (Util.hasValue(ownerName)) { owner = getRoot().getPlayerManager().getPlayerByName(ownerName); } diff --git a/src/main/java/rails/game/specific/_1880/SetupNewPublicDetails_1880.java b/src/main/java/rails/game/specific/_1880/SetupNewPublicDetails_1880.java index f484ba4de..65a9f788b 100644 --- a/src/main/java/rails/game/specific/_1880/SetupNewPublicDetails_1880.java +++ b/src/main/java/rails/game/specific/_1880/SetupNewPublicDetails_1880.java @@ -6,7 +6,9 @@ import com.google.common.base.Objects; import net.sf.rails.game.PublicCompany; +import net.sf.rails.game.RailsRoot; import net.sf.rails.game.StartItem; +import net.sf.rails.util.GameLoader; import net.sf.rails.util.RailsObjects; import net.sf.rails.util.Util; import rails.game.action.PossibleAction; @@ -45,8 +47,18 @@ public SetupNewPublicDetails_1880(StartItem startItem, private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); - if (Util.hasValue(companyName)) + if (in instanceof GameLoader.RailsObjectInputStream) { + if (Util.hasValue(companyName)) + company = getCompanyManager().getPublicCompany(companyName); + } + } + + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + + if (Util.hasValue(companyName)) { company = getCompanyManager().getPublicCompany(companyName); + } } public PublicCompany getCompany() { diff --git a/src/main/java/rails/game/specific/_18EU/StartCompany_18EU.java b/src/main/java/rails/game/specific/_18EU/StartCompany_18EU.java index d2fe38427..eeb44191d 100644 --- a/src/main/java/rails/game/specific/_18EU/StartCompany_18EU.java +++ b/src/main/java/rails/game/specific/_18EU/StartCompany_18EU.java @@ -168,21 +168,52 @@ public String toString() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (in instanceof GameLoader.RailsObjectInputStream) { + CompanyManager cmgr = root.getCompanyManager(); + if (minorsToMergeNames != null) { + minorsToMerge = new ArrayList<>(); + for (String name : minorsToMergeNames.split(",")) { + minorsToMerge.add(cmgr.getPublicCompany(name)); + } + } + if (chosenMinorName != null) { + chosenMinor = cmgr.getPublicCompany(chosenMinorName); + } + + MapManager mapManager = root.getMapManager(); + if (availableHomeStationNames != null) { + availableHomeStations = new ArrayList<>(); + for (String cityName : availableHomeStationNames.split(",")) { + String[] parts = parseStationName(cityName); + MapHex hex = mapManager.getHex(parts[0]); + int stationId = Integer.parseInt(parts[1]); + availableHomeStations.add(hex.getRelatedStop(stationId)); + } + } + // force fetching of the selected home station to prevent a load compare issue during reload + getSelectedHomeStation(); + } + } + + @Override + public void applyRailsRoot(RailsRoot root) { + super.applyRailsRoot(root); + CompanyManager cmgr = root.getCompanyManager(); - if ( minorsToMergeNames != null ) { + if (minorsToMergeNames != null) { minorsToMerge = new ArrayList<>(); - for ( String name : minorsToMergeNames.split(",") ) { + for (String name : minorsToMergeNames.split(",")) { minorsToMerge.add(cmgr.getPublicCompany(name)); } } - if ( chosenMinorName != null ) { + if (chosenMinorName != null) { chosenMinor = cmgr.getPublicCompany(chosenMinorName); } MapManager mapManager = root.getMapManager(); - if ( availableHomeStationNames != null ) { + if (availableHomeStationNames != null) { availableHomeStations = new ArrayList<>(); - for ( String cityName : availableHomeStationNames.split(",") ) { + for (String cityName : availableHomeStationNames.split(",")) { String[] parts = parseStationName(cityName); MapHex hex = mapManager.getHex(parts[0]); int stationId = Integer.parseInt(parts[1]);