np;<0_>SB*PGC@~xtBSt5iISWAd|
zHsrhpzfkwWo6O*{88hgt
zmpnCQaB2LuoW_eU5ehi1?&31PLUm>$C~PN88*#(Khpp(N^6++p61&ZF(ENWbM{7
zZ+^)Vd_$~}wYV{1kd*L5a%EW@8XTfAum9Yj)h;516?eKtEC!m-zItiLnI
zUy)-GIaK6$5IOegAJs?nldt7?3k?DxRzFsOXh9&9t#yv_xS!JDykc!~+Zu=IuyQjJ
zO1Qh(_8|IKyq3?iUf7PyOjN=w8)m&E0ZOByBf86c0
z%kCxC`@-FPsu*=H>UZfI_51a`lTZGu%2>O{oWl3H?mDxDsSSN@RPvzhP5fO!LjM7_
z;|YBWa5!qdp4%(~au=_G$8G7m^t8TT|McWjuUU${51eZtx&hweO=BiE&CgY93kx+i
zZ>pjBIaaOK%U@>ogy!ZLt1bR?vBu`?G@-^JTow+xU%*K8hLLUKqvP8~aJh>%j*jg+
zUO2vQoUe7JL)*r;Z5u7@8z0>_Zoe2Nmv2lQu?dp=KP
PJXARJe;8yvKHuK})^}I0
diff --git a/bin/data/flat_blacktiles.grf b/bin/data/flat_blacktiles.grf
new file mode 100644
index 0000000000000000000000000000000000000000..7cea4e129cdaa80c83431e2b8a380fed205c095a
GIT binary patch
literal 5878
zc%0psc~n(bmd4LM_rAyUWS&HPS{22ih%q=1MHzxa49l2kY-3r(R!fZ%wGzuAsTkV<
z&)MffKadC_A&7=nFy^6%h(uA*;8;Y_MxhKKCV*p%WsH^9-j^q#daeGeE4`{#J^p%Y
zy|uXK+u!f|_PJ|yk8Yz_!(+zAM6*~nflX%%*;k0Z&eXSknBf{&g^`6`aEBCAq<&MxC@A|$xEm-*14C5Jr
zqIbz?p5-rMGG696zG8-0qyud87OO={RSDm26Whf;XEopHDb9%o#~to;mrVLdd&`Tw
z$SR}cb8_N|WxPa}^W-v_xMM3lkj#~ZvRwX=mor%}Z_7v6Nvy(O;Bb6FJixiQ6xYdl
zxD|KHDy+gU@fP-1Hq`}%8m7i!jhdsntF>x|%2gSvTve(o>W<-?)w_D=x*vrZ8_hmUC@@HbXw(_b6(dWAfESL&$vA6&3{F7AP3QLVPdlL#58>I?1n|KIyp#DDw&Oz;p4$q3
zYN#4}Y8KxTpk7xCuTEC0l|zHgK`M7^Ax{rchmO|rv`|%3`xi*r`j=`ePwJ8d9K(yc
z!usm|G}N{BreU)+j}VuFgZr_8ESkl!c(#Nkvz_cLsc45dSP4aN3nKYKp3kpvcdf4$
zt4-GaajeuhoR@0&b9@#@Wxm9ByJ0-OiGPr-n29@ZI)0ADc#ZyVa_7_sJhAKf?j1)S
z(vJ;dF>DH3%p7bVYhuAL4&H&Ca0PsM3}3?Y_<8=2hiL<~aoVfe-)55fDBz-6Torfg
zXM--SrcLTMf>jQcW95|kN^qC+K(j?J~!tL_Shuj?RQFI90t_I~jK=2Zzmy
zZFWMs8h_w2q$xcAEu^UO8@`aV;U?ftUszw!2i7zV>j;&x{-(>Ki;PwrghUgb?z%m{S&
zI_)MBVWJOxClW@A7oGFTykd^2TTKC3T4ahHq9o%#$?D>wxF+sNt)VX*lp!)g4wA9r
zpqwdxCs(!nhe=49DcFuLc(FyEm4A{qWDa^_XY8$k)7{KjoZ9+6-{pY`_%5Ob`CgcX
z1!&+2tSSAD=XJun3XXQ?xjrgP^-(?4*rRiJwjX8gBAywbR;etNed;s5F-R4ky1-LI
z)Y1iq01>zRepa;_H-_@9oZ_#KsH?&EnDv
z6y;cT`8%34ex-pCw$+`+d^DJ^wO{SM&EnC^JoAIc|1yD6Wg44JLtaIQRNGt-d!sjl-9|rG^Oq=9kEmBBJuwX4^!Uyg_CaQ@1Z8>xv~}jVWWA
z*h;_6^%2G5SOX`gi_44%6B#LFy3A|2O0vsR
zc|z7)4l>cYCI1U;r9((wjKDz{n?K8}o*B3ZS7v?)2XQmz<9@8XZlS?o9bTuV_P9ER
z2BYliX*E*4CgG!?Z`eXNQwR-ID~+ZYW*Ju*6}zN)V=eCKO45Mzq*Th(l=
zDcVH?F|v)7Mp@a{G!WyWapPDRRqn^$d!uL)*J3*+@#+LNiI&58Y#Bq!`2Fl6yU#kq
zD3}lFPzgW40KS0d@=M&0aC=|dr`^(iPWiq{&)2`u@9BY-XD#C`Gc0dgR$G!S>6SGn
zj_bplEzRy4U|6L`a}ZAob=sPH@RZ;TpZaHcTA&E18N<{4MW6CXe6z2J$(g~ky~XQd
zA>U#X?~CN-4n2^oHGwBI1_(|s|te%PqXVw_Q#>Sxjq)g
zfroNeAu6Kq0C=fU>LnFl8i5bgI+b=(K_^w9O4W(h7VuGZ>iULJ>T@GxYYO-o1B{rX
zwGd!TGu~*j8}kii?o-BxSt$@=l$MpJHCD7hXQSn&7j*g13-H)8*G53sGb8w#ZZ}_O
z@7V{Bsb^!@cs7|*U@_&uMz)JpQuOH%0psB<%7aRHK#dzuc~He|lmp4yNm|rpHZdM8hTk!MO24!qodjLw1G}#bJ;so7(3W;
z_7(Gh{*)u@p#*NgQ+yg#?lG#2e%ilM;U3q%)xz}Q`ec2c{(JrJ?bnhaVu9(_QVoj4
zc?9%5G932E!8ioRln;_0nC*KwMt*}^(0PvT3^)!iU{loq+-$nFc04%ox*DOzUrr#w
z-o#e5LS-J9toEqGR5}|P3vNT|PWK9bP!&C!B4J(A5Kim#{~P?>OfkDY5i{H+W*3*3
zon2yvy2K1|i5cV)GtebwK)aZJ?PB`2i|NxYW~UA@Z5?8IwZqSgJ!F|YB`-S{QFT9|
zpIC3ZIF|f1|9U(BRM=l&J>K3Qr`%Mq>bc_puy+1|t7R%teQ-`mKeb;~HnxD(#XknM
z@$c#4UwIhw>g?ccyk{7+D^{nafWJw5mPXj0X1AyYqagvZp&Gn-98abt+mkL(f6$y-qvo$ilW`q-5!K**-QN;viM33%
z%(uK_NwhdD8J2&fOBUh%GwhGQ!U?VKn$)*xPu|YPPp~Zi62$}7;MaKnKmdh?@>Shb
zKPtC4_3J&$DO%K0Gknd(Q{}0>RCDK591+=G-`|+7rbd-N_)hy%ieIRz{IW>Mz)3KPnRQqXY11i=ZW)=
z=;oV(Z;_+l$ymO}4g26w97`7@i|dwqB8I%b0dukNauYAq=(2keuhk5|?_GgHmrvK;
z(U>4I%tVp1%tXPNZHb~h_xu2KdGnTG@MDV7vQf&8btTZonNXR^Qi
zmAEB;BNJqtM7c?3$bGU}UO0SDJ_0xrocP!4&uI2Cn?>lQvr^W`d|)KZgAd>c+=4EA
z9Nqf1PzpZey|l^ND(w^Pvc~nEdW`;>zM$h(9Jak>;f_G3ttyy*;4A#Ap5~ivqEF6H
zzQs+95wA8c<9V8RLo6@fzzdj25jl>h#b@HQqZaZh{l0f3(&dgW%Z@!@k+E`;BT@cB
zzMo>FF8NUIOc_RuQCHJH>Jvl_^dnxoy?n1N-Fr^duU{aVmj`_(cou-l^O~G
zN>l!s+3FefOFRWZYPwpmp*w^qsWJ{MfKXMa%C8m_)T=Akzl1L8o73(PZn$&6>Zj|X
z_&R&tu#S*wdzU+rFk3+@;(pe^ykP{)g)}$}HzACV*E_XK8t6Ur
z=k%%ieDhsyw>Fu&n%zLdbcDNv>f#crvrDMZHlddCypVRGf?PsDpg1VbWYqEe0C8PB
z%t!>kCtCTsv;rUV<-#T#bb6we?SHBT9{3bSr5pnHCwjTL^rB>7)V8HTI6y1IU*BTt;Mx5wj5oW&4}-5@WpA&3A`l(l>SDTh78wm@F7TFt@y
ztUw|NA#t>j5Rv#1LLgb{NSWhk?AWd8IrM4Or?`Dt)qz8aQ)zc$xxp?1^Hz^Zyeond
z`e4tD-Ou-a-}~0r^FE<74f6NnKOaX#azcn>E((;$8bO*48nmCC34}6d?D>#O&fOfl
z-%s5Q#_w@=DY%c90Y1HDzv6D&hW$psW%e!HkbNhhG}A#oDq=>*IY{GvBfCiR!7LqR
zFZRE_^VZ;xe_@=~*0iL%QmUVpa#`fu+TLgys;$FV!s69okID@BD<
z)mbX4HYLUL?h{_gSxnb`9z(C19GB#kM7g`oa+z|oY(H0Br^GC~ADZPsGxP%N&uanp
z*R=p6A;3s4z$9LPS;}tpH{Y*g@Bv~laUvvy%R>7(W{qri$`>MDnnq1nqM6phHQcQ8
zA{X5A?n_kI7bq`$9(Hcq8|8Q1jqO>tU27%4xuuVWa+Lc}=HsFc<)AfK!m0Rj@hFm$Kv3e2MV*E;tweCY
zZxl=W_bZ7Zq<#BIbWnYYs%k1AvUoY{6EuD^;73;0`D{8tL!0>1+_ab6g89CefV@x&
z+9(GN5-Lf@g)ExI0v(kvRaf0+b&E>#O-g=@N%)oU?lC7RejCm(0@nZ#gTwe84}43e
zm33XyUA0{|2R1sVIetWAi|%ZTj$PMHIUGC;j1Ja+hTiH;1FYv7KF}Bx$n7VPSDupm
zCQ{7FzmQ@@CfiJ9A#@Dwfy%i+{qAn!T9Fs!yq2$s9dg(9HqV1yD;9w|X`gOCMz
z1o+6qZP#A2>j5V}B{cCh-Z>7vFD^9PXq1?uD$}AqCgRB9GvCk@su*p$?)vExFaD1b
zucJgr=}Zjxshw>7P9DTXBGQzkeV89cDI%Gs{%^`>l1td{uDeCI$^^exe$B0#WM|dB
z;g+*+W153InBbrhHpQDGt7;=a}sFNyzRiz4~DyLB#v^=l0FP^FG
z=|QKsoPE`9mFwl!q~*Uo+CO*(;YrdE$g5vFS#nnU3+1%rTKLPwLMVZiAly}a4teEG
zmlUfuv8&sg=6l7m{Rvg>=5}I#RWG69_x1TN`t|wGVi=UgIR7$R^yfdjcK6QRyOSY&
z2zwtbp+M+TW6SCCoYnsE(#15(B{LnNtUy`iXYz`h_NT)y?P3uRqATttv+B0Y75f9f
zgr;i=X0nUTZ)ypZ@&{P?6;yS+gzEBOeP`mf9Z^)?f$g1hHKJQrE&gV&z5Uxlh9}}i(LhtZluR2;w))E&7!=at7K%j!KClYRh
z5RzjMBna4_wC6&)iLD0&Um=oaE@TG;E?kIKG9p$ENJL2+A?z^T?nE;02s!QuHFn52
zaV_b=Ad~-&J_7pi1UEGjf&Z0!ualP5@p(Rx+x|0hM^ANVX!$feX+1
z84wY*=NO;QBRM}79Cs)en--W)<{sg{4kuhTq#EzQ#a97oIn4u%R{
z%QBwwdWT1eZ7Pic%Do{>n|~JKKS6Au
z=h_dNv|Sh^)W(hBezrS&u#bZ~%;F{)4(kXI%1ATM=WJL=dlQRNnT5xk=l;W4J3Lxn
zdw94`*VbUkt_wr7iIq^sb}6no>@mm82Oq`g8p9Z6{uVj4E7k69BzLKhbT<+vPKemu6w*wOO93w}c+j3pbCZfr2N!6?{LQ5H!Cs*_#8Xe8-VaVOWm
E0aNpkV*mgE
diff --git a/bin/data/speedsignals.grf b/bin/data/speedsignals.grf
new file mode 100644
index 0000000000000000000000000000000000000000..b5d6488f01f189f29540528440d704faeb85bfc0
GIT binary patch
literal 2046
zc$~eHFHgfz6i4sdd#@uf!k;u`Gt)@&EEc{12_8NC^i8%l69^;{am^ebVREvv^2sas
z3Q+FGno!8L@HPPkR2G?}xhz?nGdqs0cJ5vOYkEm^e&O1RWo1NXBf;2q0zSJ0d!s#C+R`
zU{3@fG_q-zh7)ei@Hu0#VMh69uN?8JI-(ymfX}-vbPMt+ZixGSG%bf!uI90A=N^QM
z;H|;Mm&Z6ve-d}v3JW?ZnBe1+tY1W6-GAkwl~qTu#_?SbX<0dlNRnPvq-&Gt7v>y_3Cv^wtHS?
zKIl$nW%nzb%x1X}p_-OV@|-Y~rA5A?Qmt5!y|cJjC~!mMlwy%@ixs2^ys4@tV@&=`
zm7kYipT6y3L`bl<+woW|DvPd9PHOh$LLFU=X_^Gx3B^uvvO$8%eS)Gp2~^_CJ4Df=
zJi+JuYIALw)9z=a@3xWd4%ApI9(TWDUDpLZ@yQnLBu@26G>YuWljAPkQxCPX2jZC1
zz5C9$7X54F@NqAON*(gYOZl0SvRlNLL(blJ6Jk!0f~brItp_f_zNKXa^xl?O#l9r!HQ|6u9O!%sz|e^}?_cn{fw7hhgF6RwVJ8-08ivF%c+H1sH*
zJ^~a|;pfHoi|If(Gfk*gOsG{ESSbc+i$Ol;!9v~xf7{cpiZoa4-a;@6&CD~%WHN=TB%2M%HYD4;mg`8iACetM?r7H6JbZ>F3MQ*c-SS?TmK>ZGh9)&LU$Z~Ed{+KF
ep_|Z*M6==0hD4j!QstFm{cz|QQg1|q@$ef;NFme!
diff --git a/bin/data/trafficlights_dark.grf b/bin/data/trafficlights_dark.grf
new file mode 100644
index 0000000000000000000000000000000000000000..a68b99852c5f15bcec4a819e704694b8c8187445
GIT binary patch
literal 1710
zc$}@2O-LI-6oB9CY(iN#Ne|oNDZ7H$6iP3W%|$~^Eerk6-5Bp2Cu^0?+S779HyV4>8$-Pj*cLW2%0v&_slZ{GKYS!GPq
zz-yd7!JXiSilePN+%OEmC1Y$=EQ41J~GC7GEp-J;|xF{P+K1Z`tJfF*nbu
zqo2{@v*N4cH*L;z-9OvSNH`p#rm7<&ihX`iN0q~hLZBOz>^SPHy5G5vSZFiK3b?ST
zOKJ$CnDn}}qawrtOi0MW{(^lwv26gUpcua
z4$;`Y>wK*ne~j!uY=>E)ssHv;d?Ll|y6(x*Pu{hnA}Ns|gTjK+23O~vr3DGp_PSW&
zo-6%iuYD@kCGw?rZ?j0VA(1l!8xln7Nnf1aoog=1zPqJvd`tK2t#35Ar_U&wv|F@+(!C(+d2|_wG
z6k6M1uv_~Z)j6=B;|zsfL)3xjPeLbrlraQWDg%})fN>MhOn{Zif|Z^1P_V>A9~JR|
z=u8SQl^zP+sR7n@0jH(`r;}hEIAA%Qq0lQt{hwSt!~I9)CL)xPt^}DjX`6(QSypJl
zS+sySnZae%xyYu7O%KV|h~51su0w2RNcKA74rV>g{b!g^U|1&IbT61mixWaqNHcnx
nz1=0aP@&7v6rt(i&>EpsTsBQ;l2E!**clGJLezn|`s?8rX|oY-
diff --git a/bin/data/trafficlights_light.grf b/bin/data/trafficlights_light.grf
new file mode 100644
index 0000000000000000000000000000000000000000..def76c5420a4ff65a8ef13bd71405ddb9d881097
GIT binary patch
literal 1710
zc$}@2J!l&-7=}Nc&Y@h+c86=pWa%KJDwHn9=Ou*3UOIHJLt-xtcnEYj=u#*h(p@ec
z0-=zQCHM!@PD$*+aTkYDu$OSol=0$8DHJ;NAcfLYcTSto2E%~`hYm@PUg?q02114b
ze!=n+*qPYY`Be8Frj!b-P;NRnPvq-&Gt7v>y_3Cv^wtHS?
zKIl$nW%nzb%x1X}p_-OV@|-Y~rA5A?Qmt5!y|cJjC~!mMlwy%@ixs2^ys4@tV@&=`
zm7kYipT6y3L`bl<+woW|DvPd9PHOh$LLFU=X_^Gx3B^uvvO$8%eS)Gp2~^_CJ4Df=
zJi+JuYIALw)9z=a@3xWd4%ApI9(TWDUDpLZ@yQnLBu@26G>YuWljAPkQxCPX2jZC1
zz5C9$7X54F@NqAON*(gYOZl0SvRlNLL(blJ6Jk!0f~brItp_f_zNKXa^xl?O#l9r!HQ|6u9O!%sz|e^}?_cn{fw7hhgF6RwVJ8-08ivF%c+H1sH*
zJ^~a|;pfHoi|If(Gfk*gOsG{ESSbc+i$Ol;!9v~xf7{cpiZoa4-a;@6&CD~%WHN=TB%2M%HYD4;mg`8iACetM?r7H6JbZ>F3MQ*c-SS?TmK>ZGh9)&LU$Z~Ed{+KF
ep_|Z*M6==0hD4j!QstFm{cz|QQg1|q@$ef;NFme!
diff --git a/bin/data/trafficlights_wooden.grf b/bin/data/trafficlights_wooden.grf
new file mode 100644
index 0000000000000000000000000000000000000000..98e229436a2dfaa1512f6ee997492191c91113b1
GIT binary patch
literal 1712
zc$}@2KS*0a9LIn6?j@A?k~q8;r(6cHEtD>jmqnx|ONS1LXtGquAar<8$h())!S0vR
zL6CytBKZThlbQ@MT_UBBEb`*y_{?+`3LQE)l-j!&TLmTXAP0|o+}-ECcb_|M6Cqs(
zS+Mvxc7i(^o9aHq#bS|TrD$#H*tTts5oNkktuS3J+VvX0&mINpwOXab=2W|0FNt>B
zPAz!dvuV-&7SE>BOb--GrP*1Q;kvTC#8%Z}DW4O)b2y*NF`Z|We4g#_RaD}5OI0mO
zsrZ>Hzb?N!`_RLP5N~ah(MTjLil$9Wgv_gjI+_{@g+d&=LB&ikvPrzkeSyNeF;rkH
zyF}5#EXL+#wY9#&;@xjZ+iN4u9jK8=H0u7qnx=7lD#=#76Fbua;V?2MPEWe=ef21G
z{)C^f`2J((XDj~S$kFp&1Qj~upO^A0C1JLRlta!xbz^*95rX0(7D7F636_>t6wrFx
zd<{!iLXHE6otql@;MB3ZlX=AA`UN*#R
zoi-;ZC$}vc^Xy`sNQvc*L*q(g`QUK*{nM{`qar=
zry{uPbZ)aL!KQt(4Z${VGr
gaO;HbLQ?`w`$HQ7ZQe)~SBm!ip<_tB6ZOW!U)pdu%K!iX
diff --git a/config.lib b/config.lib
--- a/config.lib
+++ b/config.lib
@@ -1288,9 +1288,6 @@ make_compiler_cflags() {
# sure that they will not happen. It furthermore complains
# about its own optimized code in some places.
flags="$flags -fno-strict-overflow"
- # GCC 4.2 no longer includes -Wnon-virtual-dtor in -Wall.
- # Enable it in order to be consistent with older GCC versions.
- flags="$flags -Wnon-virtual-dtor"
fi
if [ $cc_version -ge 43 ]; then
@@ -1420,7 +1417,7 @@ make_cflags_and_ldflags() {
LIBS="$LIBS -lws2_32 -lwinmm -lgdi32 -ldxguid -lole32"
if [ $cc_version -ge 44 ]; then
- LDFLAGS_BUILD="$LDFLAGS_BUILD -static-libgcc -static-libstdc++"
+ LDFLAGS_BUILD="$LDFLAGS_BUILD -static-libgcc"
fi
fi
fi
@@ -3099,7 +3096,6 @@ make_sed() {
s@!!SRC_OBJS_DIR!!@$SRC_OBJS_DIR@g;
s@!!LANG_OBJS_DIR!!@$LANG_OBJS_DIR@g;
s@!!GRF_OBJS_DIR!!@$GRF_OBJS_DIR@g;
- s@!!SETTING_OBJS_DIR!!@$SETTING_OBJS_DIR@g;
s@!!SRC_DIR!!@$SRC_DIR@g;
s@!!SCRIPT_SRC_DIR!!@$SCRIPT_SRC_DIR@g;
s@!!OSXAPP!!@$OSXAPP@g;
@@ -3118,7 +3114,6 @@ make_sed() {
s@!!STRGEN!!@$STRGEN@g;
s@!!ENDIAN_CHECK!!@$ENDIAN_CHECK@g;
s@!!DEPEND!!@$DEPEND@g;
- s@!!SETTINGSGEN!!@$SETTINGSGEN@g;
s@!!ENDIAN_FORCE!!@$endian@g;
s@!!STAGE!!@$STAGE@g;
s@!!MAKEDEPEND!!@$makedepend@g;
@@ -3226,20 +3221,6 @@ generate_lang() {
echo "LANG_DIRS += $LANG_OBJS_DIR" >> Makefile.am
}
-generate_settings() {
- STAGE="[SETTING]"
-
- make_sed
-
- # Create the language file
- mkdir -p $SETTING_OBJS_DIR
-
- log 1 "Generating setting/Makefile..."
- echo "# Auto-generated file from 'Makefile.settings.in' -- DO NOT EDIT" > $SETTING_OBJS_DIR/Makefile
- < $ROOT_DIR/Makefile.setting.in sed "$SRC_REPLACE" >> $SETTING_OBJS_DIR/Makefile
- echo "DIRS += $SETTING_OBJS_DIR" >> Makefile.am
-}
-
generate_grf() {
STAGE="[GRF]"
diff --git a/configure b/configure
--- a/configure
+++ b/configure
@@ -48,7 +48,6 @@ OBJS_DIR="$PWD/objs"
BASE_SRC_OBJS_DIR="$OBJS_DIR"
LANG_OBJS_DIR="$OBJS_DIR/lang"
GRF_OBJS_DIR="$OBJS_DIR/extra_grf"
-SETTING_OBJS_DIR="$OBJS_DIR/setting"
BIN_DIR="$PREFIX"
SRC_DIR="$ROOT_DIR/src"
LANG_DIR="$SRC_DIR/lang"
@@ -83,7 +82,6 @@ TTD="openttd$EXE"
STRGEN="strgen$EXE"
ENDIAN_CHECK="endian_check$EXE"
DEPEND="depend$EXE"
-SETTINGSGEN="settings_gen$EXE"
if [ -z "$sort" ]; then
PIPE_SORT="sed s@a@a@"
@@ -163,11 +161,10 @@ else
sort="$sort -u"
fi
-CONFIGURE_FILES="$ROOT_DIR/configure $ROOT_DIR/config.lib $ROOT_DIR/Makefile.in $ROOT_DIR/Makefile.grf.in $ROOT_DIR/Makefile.lang.in $ROOT_DIR/Makefile.src.in $ROOT_DIR/Makefile.bundle.in $ROOT_DIR/Makefile.setting.in"
+CONFIGURE_FILES="$ROOT_DIR/configure $ROOT_DIR/config.lib $ROOT_DIR/Makefile.in $ROOT_DIR/Makefile.grf.in $ROOT_DIR/Makefile.lang.in $ROOT_DIR/Makefile.src.in $ROOT_DIR/Makefile.bundle.in"
generate_main
generate_lang
-generate_settings
generate_grf
generate_src
diff --git a/docs/copy_paste_array.txt b/docs/copy_paste_array.txt
new file mode 100644
--- /dev/null
+++ b/docs/copy_paste_array.txt
@@ -0,0 +1,62 @@
+m_tiletype:
+ bits 0..3: tiletype
+ bits 4..7: minor tiletype
+
+m_heightmap:
+ storing height relative to the northern corner
+m_terrain_needed:
+ bit 0 set: paste height if terraform level is 1
+
+tiletypes:
+ CP_TILE_RAIL:
+ minor tiletype: RailTileType
+ m_railroad bits 6..7: RailType(monorail, maglev, electric, normal)
+ RailTileTypes:
+ RAIL_TILE_DEPOT:
+ m_railroad bits 0..1: depot direction
+ RAIL_TILE_WAYPOINT:
+ m_signals bits 0..7: waypoint grf id
+ m_railroad bits 0..1: waypoint direction
+ RAIL_TILE_SIGNALS:
+ m_signals bit 0 set: signal 1 present
+ m_signals bit 1 set: signal 2 present
+ m_signals bit 2 set: first signal is semaphore
+ m_signals bit 3 set: second signal is semaphore
+ m_signals bits 6..7 : first signal direction
+ m_signals bits 8..9 : second signal direction
+ m_signals bits 10..12: first signal type
+ m_signals bits 13..15: second signal type
+ RAIL_TILE_NORMAL and RAIL_TILE_SIGNALS:
+ m_railroad bits 0..5: trackbits
+
+ CP_TILE_ROAD:
+ minor tiletype: RoadTileType
+ RoadTileTypes:
+ ROAD_TILE_DEPOT:
+ m_railroad bits 0..1: depot direction
+ m_railroad bit 2 set: tram depot
+ ROAD_TILE_CROSSING, ROAD_TILE_NORMAL:
+ m_railroad bits 0..3: RoadBits normal road
+ m_railroad bits 4..7: RoadBits tram
+ ROAD_TILE_NORMAL:
+ m_signals bits 0..1: disallowed road directions
+ ROAD_TILE_CROSSING:
+ m_railroad bits 6..7: rail type
+
+ CP_TILE_TUNNELBRIDGE:
+ minor tiletype bit 0 set: tunnel
+ m_railroad bit 0..1: direction
+ m_railroad bit 2..3: transporttype
+ m_railroad bit 4 set: start
+ m_railroad bit 6..7: rail/roadtypes
+
+ CP_TILE_STATION:
+ minor tiletype: TileType (minor bits indicate station type)
+ TileType:
+ CP_TILE_ROAD:
+ m_railroad bits 0..1: direction
+ m_railroad bit 2 set: truck stop
+ m_railroad bit 3 set: drive through
+ (3..5 currently unused)
+ m_railroad bits 6..7: road type
+ CP_TILE_RAIL:
diff --git a/docs/linkgraph.txt b/docs/linkgraph.txt
new file mode 100644
--- /dev/null
+++ b/docs/linkgraph.txt
@@ -0,0 +1,30 @@
+Some clarifications about the link graph
+----------------------------------------
+
+InitializeLinkGraphs joins all threads, so if the game is abendoned
+with some threads still running, they're joined as soon as the next game
+(possibly the title game) is started. see also InitializeGame.
+
+The MCF algorithm can be quite CPU-hungry as it's NP-hard and takes
+exponential time (though with a very small constant factor) in the number
+of nodes.
+This is why it is run in a separate thread where possible. However after
+some time the thread is joined and if it hasn't finished by then the game
+will hang. This problem gets worse if we are running on a platform without
+threads. However, as those are usually the ones with less CPU power I
+assume the contention for the CPU would make the game hard to play even
+with threads or even without cargodist (autosave ...). I might be wrong,
+but I won't put any work into this before someone shows me some problem.
+
+You can configure the link graph recalculation interval. A link graph
+recalculation interval of X days means that each link graph job has X days
+to run before it is joined. The downside is that the flow stats won't be
+updated before the job is finished and thus a long interval means less
+updates and longer times until changes in capacities are accounted for.
+If you play a very large map with a complicated link graph you may want to
+raise the interval to avoid lags. The same holds for systems with slow
+CPUs.
+
+Another option to avoid excessive lags is to reduce the accuracy of link
+graph calculations. Generally the accurace is inversely correlated to the
+CPU requirements of the MCF algorithm.
diff --git a/projects/generate b/projects/generate
--- a/projects/generate
+++ b/projects/generate
@@ -77,7 +77,7 @@ safety_check() {
done
}
-grep '\.h' "$ROOT_DIR/source.list" | grep -v '../objs/langs/table/strings.h\|../objs/settings/table/settings.h' | sed 's/ //' | sort > tmp.headers.source.list
+grep '\.h' "$ROOT_DIR/source.list" | grep -v '../objs/langs/table/strings.h' | sed 's/ //' | sort > tmp.headers.source.list
find "$ROOT_DIR/src" \( -iname "*.h" -or -iname "*.hpp" \) -and -not -ipath "*/.svn/*" | sed "s~$ROOT_DIR/src/~~" | sort > tmp.headers.src
if [ -n "`diff tmp.headers.source.list tmp.headers.src`" ]; then
echo "The following headers are missing in source.list and not in /src/ or vice versa."
@@ -204,28 +204,6 @@ load_lang_data() {
eval "$2=\"\$RES\""
}
-load_settings_data() {
- RES=""
- RES2="
-#3..\\objs\\settings\\settings_gen.exe -o ..\\objs\\settings\\table\\settings.h -b ..\\src\\table\\settings.h.preamble -a ..\\src\\table\\settings.h.postamble"
- for i in `ls $1`
- do
- i=`basename $i`
- RES="$RES
-#1
-#1
-#2
-#4
-#4 INI
-#4 "
- RES2="$RES2 ..\\src\\table\\"$i
- done
-
- eval "$2=\"\$RES\$RES2\""
-}
-
generate() {
echo "Generating $2..."
if [ $# -eq 3 ]; then
@@ -288,12 +266,6 @@ load_lang_data "$ROOT_DIR/src/lang/*.txt
langvcxproj=`echo "$lang" | grep "^#2" | sed "s~#2~~g"`
lang=`echo "$lang" | grep "^#1" | sed "s~#1~~g"`
-load_settings_data "$ROOT_DIR/src/table/*.ini" settings
-settingsfiles=`echo "$settings" | grep "^#4" | sed "s~#4~~g"`
-settingscommand=`echo "$settings" | grep "^#3" | sed "s~#3~~g"`
-settingsvcxproj=`echo "$settings" | grep "^#2" | sed "s~#2~~g"`
-settings=`echo "$settings" | grep "^#1" | sed "s~#1~~g"`
-
generate "$openttd" "openttd_vs80.vcproj"
generate "$openttd" "openttd_vs90.vcproj"
generate "$openttdvcxproj" "openttd_vs100.vcxproj"
@@ -301,7 +273,3 @@ generate "$openttdfiles" "openttd_vs100.
generate "$lang" "langs_vs80.vcproj"
generate "$lang" "langs_vs90.vcproj"
generate "$langvcxproj" "langs_vs100.vcxproj"
-generate "$settings" "settings_vs80.vcproj" "$settingscommand"
-generate "$settings" "settings_vs90.vcproj" "$settingscommand"
-generate "$settingsvcxproj" "settings_vs100.vcxproj" "$settingscommand"
-generate "$settingsfiles" "settings_vs100.vcxproj.filters"
diff --git a/projects/generate.vbs b/projects/generate.vbs
--- a/projects/generate.vbs
+++ b/projects/generate.vbs
@@ -113,7 +113,7 @@ Sub headers_check(filename, dir)
Set file = FSO.OpenTextFile(filename, 1, 0, 0)
While Not file.AtEndOfStream
line = Replace(file.ReadLine, Chr(9), "") ' Remove tabs
- If Len(line) > 0 And regexp.Test(line) And line <> "../objs/langs/table/strings.h" And line <> "../objs/settings/table/settings.h" Then
+ If Len(line) > 0 And regexp.Test(line) And line <> "../objs/langs/table/strings.h" Then
source_list_headers.Add line, line
End If
Wend
@@ -274,38 +274,6 @@ Function load_lang_data(dir, ByRef vcxpr
load_lang_data = res
End Function
-Function load_settings_data(dir, ByRef vcxproj, ByRef command, ByRef files)
- Dim res, folder, file, first_time
- res = ""
- command = "..\objs\settings\settings_gen.exe -o ..\objs\settings\table\settings.h -b ..\src\table\settings.h.preamble -a ..\src\table\settings.h.postamble"
- Set folder = FSO.GetFolder(dir)
- For Each file In folder.Files
- file = FSO.GetFileName(file)
- If FSO.GetExtensionName(file) = "ini" Then
- if first_time <> 0 Then
- res = res & vbCrLf
- vcxproj = vcxproj & vbCrLf
- files = files & vbCrLf
- Else
- first_time = 1
- End If
- res = res & _
- " " & vbCrLf & _
- " "
- vcxproj = vcxproj & _
- " "
- command = command & " ..\src\table\" & file
- files = files & _
- " " & vbCrLf & _
- " INI " & vbCrLf & _
- " "
- End If
- Next
- load_settings_data = res
-End Function
-
Sub generate(data, dest, data2)
Dim srcfile, destfile, line
WScript.Echo "Generating " & FSO.GetFileName(dest) & "..."
@@ -369,10 +337,3 @@ lang = load_lang_data(ROOT_DIR & "/src/l
generate lang, ROOT_DIR & "/projects/langs_vs80.vcproj", Null
generate lang, ROOT_DIR & "/projects/langs_vs90.vcproj", Null
generate langvcxproj, ROOT_DIR & "/projects/langs_vs100.vcxproj", Null
-
-Dim settings, settingsvcxproj, settingscommand, settingsfiles
-settings = load_settings_data(ROOT_DIR & "/src/table", settingsvcxproj, settingscommand, settingsfiles)
-generate settings, ROOT_DIR & "/projects/settings_vs80.vcproj", settingscommand
-generate settings, ROOT_DIR & "/projects/settings_vs90.vcproj", settingscommand
-generate settingsvcxproj, ROOT_DIR & "/projects/settings_vs100.vcxproj", settingscommand
-generate settingsfiles, ROOT_DIR & "/projects/settings_vs100.vcxproj.filters", Null
diff --git a/projects/openttd_vs100.sln b/projects/openttd_vs100.sln
--- a/projects/openttd_vs100.sln
+++ b/projects/openttd_vs100.sln
@@ -1,10 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual C++ Express 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openttd", "openttd_vs100.vcxproj", "{668328A0-B40E-4CDB-BD72-D0064424414A}"
- ProjectSection(ProjectDependencies) = postProject
- {0817F629-589E-4A3B-B81A-8647BC571E35} = {0817F629-589E-4A3B-B81A-8647BC571E35}
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7} = {E9548DE9-F089-49B7-93A6-30BE2CC311C7}
- EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "strgen", "strgen_vs100.vcxproj", "{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}"
EndProject
@@ -14,13 +10,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C9
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate", "generate_vs100.vcxproj", "{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settings", "settings_vs100.vcxproj", "{0817F629-589E-4A3B-B81A-8647BC571E35}"
- ProjectSection(ProjectDependencies) = postProject
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7} = {E9548DE9-F089-49B7-93A6-30BE2CC311C7}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settingsgen", "settingsgen_vs100.vcxproj", "{E9548DE9-F089-49B7-93A6-30BE2CC311C7}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -65,22 +54,6 @@ Global
{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Debug|x64.ActiveCfg = Debug|Win32
{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Release|Win32.ActiveCfg = Debug|Win32
{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Release|x64.ActiveCfg = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|Win32.ActiveCfg = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|Win32.Build.0 = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|x64.ActiveCfg = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|x64.Build.0 = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|Win32.ActiveCfg = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|Win32.Build.0 = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|x64.ActiveCfg = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|x64.Build.0 = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|Win32.ActiveCfg = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|Win32.Build.0 = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|x64.ActiveCfg = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|x64.Build.0 = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|Win32.ActiveCfg = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|Win32.Build.0 = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|x64.ActiveCfg = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|x64.Build.0 = Debug|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj
--- a/projects/openttd_vs100.vcxproj
+++ b/projects/openttd_vs100.vcxproj
@@ -101,7 +101,7 @@
true
Size
true
- ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories)
+ ..\objs\langs;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories)
WIN32;NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";WITH_ASSERT;%(PreprocessorDefinitions)
true
Sync
@@ -155,7 +155,7 @@
/MP %(AdditionalOptions)
Disabled
- ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories)
+ ..\objs\langs;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories)
WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions)
EnableFastChecks
MultiThreadedDebug
@@ -203,7 +203,7 @@
true
Size
true
- ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories)
+ ..\objs\langs;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories)
WIN32;NDEBUG;_CONSOLE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;WITH_ASSERT;%(PreprocessorDefinitions)
true
Sync
@@ -255,7 +255,7 @@
/MP %(AdditionalOptions)
Disabled
- ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories)
+ ..\objs\langs;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories)
WIN32;_DEBUG;_CONSOLE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions)
EnableFastChecks
MultiThreadedDebug
@@ -300,13 +300,16 @@
+
+
+
@@ -324,12 +327,17 @@
+
-
+
+
+
+
+
@@ -343,6 +351,7 @@
+
@@ -364,6 +373,7 @@
+
@@ -402,6 +412,8 @@
+
+
@@ -409,6 +421,9 @@
+
+
+
@@ -451,14 +466,21 @@
+
+
+
+
+
+
+
@@ -514,6 +536,7 @@
+
@@ -579,6 +602,9 @@
+
+
+
@@ -591,6 +617,7 @@
+
@@ -619,6 +646,7 @@
+
@@ -637,7 +665,9 @@
+
+
@@ -660,6 +690,7 @@
+
@@ -679,6 +710,7 @@
+
@@ -725,6 +757,7 @@
+
@@ -738,6 +771,7 @@
+
@@ -769,7 +803,7 @@
-
+
diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters
--- a/projects/openttd_vs100.vcxproj.filters
+++ b/projects/openttd_vs100.vcxproj.filters
@@ -120,12 +120,18 @@
Source Files
+
+ Source Files
+
Source Files
Source Files
+
+ Source Files
+
Source Files
@@ -141,6 +147,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -192,13 +201,25 @@
Source Files
+
+ Source Files
+
Source Files
-
+
Source Files
-
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
Source Files
@@ -210,6 +231,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -249,6 +273,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -312,6 +339,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -426,6 +456,12 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
Header Files
@@ -447,6 +483,15 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
Header Files
@@ -573,6 +618,9 @@
Header Files
+
+ Header Files
+
Header Files
@@ -585,6 +633,21 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
Header Files
@@ -597,6 +660,9 @@
Header Files
+
+ Header Files
+
Header Files
@@ -762,6 +828,9 @@
Header Files
+
+ Header Files
+
Header Files
@@ -957,6 +1026,15 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
Header Files
@@ -993,6 +1071,9 @@
Header Files
+
+ Header Files
+
Header Files
@@ -1077,6 +1158,9 @@
Core Source Code
+
+ Core Source Code
+
Core Source Code
@@ -1131,9 +1215,15 @@
GUI Source Code
+
+ GUI Source Code
+
GUI Source Code
+
+ GUI Source Code
+
GUI Source Code
@@ -1200,6 +1290,9 @@
GUI Source Code
+
+ GUI Source Code
+
GUI Source Code
@@ -1257,6 +1350,9 @@
GUI Source Code
+
+ GUI Source Code
+
GUI Source Code
@@ -1395,6 +1491,9 @@
Save/Load handlers
+
+ Save/Load handlers
+
Save/Load handlers
@@ -1434,6 +1533,9 @@
Save/Load handlers
+
+ Save/Load handlers
+
Save/Load handlers
@@ -1527,7 +1629,7 @@
Tables
-
+
Tables
diff --git a/projects/openttd_vs100.vcxproj.in b/projects/openttd_vs100.vcxproj.in
--- a/projects/openttd_vs100.vcxproj.in
+++ b/projects/openttd_vs100.vcxproj.in
@@ -101,7 +101,7 @@
true
Size
true
- ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories)
+ ..\objs\langs;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories)
WIN32;NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";WITH_ASSERT;%(PreprocessorDefinitions)
true
Sync
@@ -155,7 +155,7 @@
/MP %(AdditionalOptions)
Disabled
- ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories)
+ ..\objs\langs;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories)
WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions)
EnableFastChecks
MultiThreadedDebug
@@ -203,7 +203,7 @@
true
Size
true
- ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories)
+ ..\objs\langs;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories)
WIN32;NDEBUG;_CONSOLE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;WITH_ASSERT;%(PreprocessorDefinitions)
true
Sync
@@ -255,7 +255,7 @@
/MP %(AdditionalOptions)
Disabled
- ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories)
+ ..\objs\langs;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories)
WIN32;_DEBUG;_CONSOLE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions)
EnableFastChecks
MultiThreadedDebug
diff --git a/projects/openttd_vs80.sln b/projects/openttd_vs80.sln
--- a/projects/openttd_vs80.sln
+++ b/projects/openttd_vs80.sln
@@ -3,8 +3,8 @@ Microsoft Visual Studio Solution File, F
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openttd", "openttd_vs80.vcproj", "{668328A0-B40E-4CDB-BD72-D0064424414A}"
ProjectSection(ProjectDependencies) = postProject
{0F066B23-18DF-4284-8265-F4A5E7E3B966} = {0F066B23-18DF-4284-8265-F4A5E7E3B966}
+ {A133A442-BD0A-4ADE-B117-AD7545E4BDD1} = {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}
{1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC} = {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}
- {0817F629-589E-4A3B-B81A-8647BC571E35} = {0817F629-589E-4A3B-B81A-8647BC571E35}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "strgen", "strgen_vs80.vcproj", "{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}"
@@ -18,13 +18,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C9
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate", "generate_vs80.vcproj", "{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settings", "settings_vs80.vcproj", "{0817F629-589E-4A3B-B81A-8647BC571E35}"
- ProjectSection(ProjectDependencies) = postProject
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7} = {E9548DE9-F089-49B7-93A6-30BE2CC311C7}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settings_gen", "settingsgen_vs80.vcproj", "{E9548DE9-F089-49B7-93A6-30BE2CC311C7}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -69,22 +62,6 @@ Global
{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Debug|x64.ActiveCfg = Debug|Win32
{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Release|Win32.ActiveCfg = Debug|Win32
{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Release|x64.ActiveCfg = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|Win32.ActiveCfg = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|Win32.Build.0 = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|x64.ActiveCfg = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|x64.Build.0 = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|Win32.ActiveCfg = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|Win32.Build.0 = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|x64.ActiveCfg = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|x64.Build.0 = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|Win32.ActiveCfg = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|Win32.Build.0 = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|x64.ActiveCfg = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|x64.Build.0 = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|Win32.ActiveCfg = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|Win32.Build.0 = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|x64.ActiveCfg = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|x64.Build.0 = Debug|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj
--- a/projects/openttd_vs80.vcproj
+++ b/projects/openttd_vs80.vcproj
@@ -51,7 +51,7 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include"
+ AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR=\"OpenTTD\";WITH_ASSERT"
StringPooling="true"
ExceptionHandling="1"
@@ -155,7 +155,7 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
- AdditionalIncludeDirectories="..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include"
+ AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR=\"OpenTTD\""
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -256,7 +256,7 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include"
+ AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR=\"OpenTTD\";_SQ64;WITH_ASSERT"
StringPooling="true"
ExceptionHandling="1"
@@ -361,7 +361,7 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
- AdditionalIncludeDirectories="..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include"
+ AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR=\"OpenTTD\";_SQ64"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -471,6 +471,10 @@
>
+
+
@@ -483,6 +487,10 @@
>
+
+
@@ -499,6 +507,10 @@
>
+
+
@@ -567,18 +579,34 @@
>
+
+
-
-
+
+
+
+
+
+
+
+
@@ -591,6 +619,10 @@
>
+
+
@@ -643,6 +675,10 @@
>
+
+
@@ -823,6 +859,14 @@
>
+
+
+
+
@@ -911,6 +955,18 @@
>
+
+
+
+
+
+
@@ -1079,6 +1135,10 @@
>
+
+
@@ -1095,6 +1155,26 @@
>
+
+
+
+
+
+
+
+
+
+
@@ -1111,6 +1191,10 @@
>
+
+
@@ -1331,6 +1415,10 @@
>
+
+
@@ -1586,6 +1674,18 @@
RelativePath=".\..\src\track_type.h"
>
+
+
+
+
+
+
@@ -1643,6 +1743,10 @@
>
+
+
@@ -1755,6 +1859,10 @@
>
+
+
@@ -1835,6 +1943,14 @@
>
+
+
+
+
@@ -1923,6 +2039,10 @@
>
+
+
@@ -1999,6 +2119,10 @@
>
+
+
@@ -2195,6 +2319,10 @@
>
+
+
@@ -2247,6 +2375,10 @@
>
+
+
@@ -2375,7 +2507,7 @@
>
+
+
diff --git a/projects/openttd_vs80.vcproj.in b/projects/openttd_vs80.vcproj.in
--- a/projects/openttd_vs80.vcproj.in
+++ b/projects/openttd_vs80.vcproj.in
@@ -51,7 +51,7 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include"
+ AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR=\"OpenTTD\";WITH_ASSERT"
StringPooling="true"
ExceptionHandling="1"
@@ -155,7 +155,7 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
- AdditionalIncludeDirectories="..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include"
+ AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR=\"OpenTTD\""
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -256,7 +256,7 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include"
+ AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR=\"OpenTTD\";_SQ64;WITH_ASSERT"
StringPooling="true"
ExceptionHandling="1"
@@ -361,7 +361,7 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
- AdditionalIncludeDirectories="..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include"
+ AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR=\"OpenTTD\";_SQ64"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
diff --git a/projects/openttd_vs90.sln b/projects/openttd_vs90.sln
--- a/projects/openttd_vs90.sln
+++ b/projects/openttd_vs90.sln
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, F
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openttd", "openttd_vs90.vcproj", "{668328A0-B40E-4CDB-BD72-D0064424414A}"
ProjectSection(ProjectDependencies) = postProject
{0F066B23-18DF-4284-8265-F4A5E7E3B966} = {0F066B23-18DF-4284-8265-F4A5E7E3B966}
- {0817F629-589E-4A3B-B81A-8647BC571E35} = {0817F629-589E-4A3B-B81A-8647BC571E35}
+ {A133A442-BD0A-4ADE-B117-AD7545E4BDD1} = {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}
{1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC} = {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}
EndProjectSection
EndProject
@@ -18,13 +18,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C9
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate", "generate_vs90.vcproj", "{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settings", "settings_vs90.vcproj", "{0817F629-589E-4A3B-B81A-8647BC571E35}"
- ProjectSection(ProjectDependencies) = postProject
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7} = {E9548DE9-F089-49B7-93A6-30BE2CC311C7}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settingsgen", "settingsgen_vs90.vcproj", "{E9548DE9-F089-49B7-93A6-30BE2CC311C7}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -69,22 +62,6 @@ Global
{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Debug|x64.ActiveCfg = Debug|Win32
{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Release|Win32.ActiveCfg = Debug|Win32
{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Release|x64.ActiveCfg = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|Win32.ActiveCfg = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|Win32.Build.0 = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|x64.ActiveCfg = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|x64.Build.0 = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|Win32.ActiveCfg = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|Win32.Build.0 = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|x64.ActiveCfg = Debug|Win32
- {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|x64.Build.0 = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|Win32.ActiveCfg = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|Win32.Build.0 = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|x64.ActiveCfg = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|x64.Build.0 = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|Win32.ActiveCfg = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|Win32.Build.0 = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|x64.ActiveCfg = Debug|Win32
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|x64.Build.0 = Debug|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj
--- a/projects/openttd_vs90.vcproj
+++ b/projects/openttd_vs90.vcproj
@@ -52,7 +52,7 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include"
+ AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR=\"OpenTTD\";WITH_ASSERT"
StringPooling="true"
ExceptionHandling="1"
@@ -154,7 +154,7 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
- AdditionalIncludeDirectories="..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include"
+ AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR=\"OpenTTD\""
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -254,7 +254,7 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include"
+ AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR=\"OpenTTD\";_SQ64;WITH_ASSERT"
StringPooling="true"
ExceptionHandling="1"
@@ -358,7 +358,7 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
- AdditionalIncludeDirectories="..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include"
+ AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR=\"OpenTTD\";_SQ64"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -468,6 +468,10 @@
>
+
+
@@ -480,6 +484,10 @@
>
+
+
@@ -496,6 +504,10 @@
>
+
+
@@ -564,18 +576,34 @@
>
+
+
-
-
+
+
+
+
+
+
+
+
@@ -588,6 +616,10 @@
>
+
+
@@ -640,6 +672,10 @@
>
+
+
@@ -840,6 +876,10 @@
>
+
+
@@ -884,6 +924,10 @@
>
+
+
@@ -908,6 +952,18 @@
>
+
+
+
+
+
+
@@ -1076,6 +1132,10 @@
>
+
+
@@ -1092,6 +1152,26 @@
>
+
+
+
+
+
+
+
+
+
+
@@ -1108,6 +1188,10 @@
>
+
+
@@ -1328,6 +1412,10 @@
>
+
+
@@ -1583,6 +1671,18 @@
RelativePath=".\..\src\track_type.h"
>
+
+
+
+
+
+
@@ -1636,6 +1736,10 @@
>
+
+
@@ -1752,6 +1856,10 @@
>
+
+
@@ -1832,6 +1940,14 @@
>
+
+
+
+
@@ -1920,6 +2036,10 @@
>
+
+
@@ -1996,6 +2116,10 @@
>
+
+
@@ -2192,6 +2316,10 @@
>
+
+
@@ -2244,6 +2372,10 @@
>
+
+
@@ -2372,7 +2504,7 @@
>
+
+
diff --git a/projects/openttd_vs90.vcproj.in b/projects/openttd_vs90.vcproj.in
--- a/projects/openttd_vs90.vcproj.in
+++ b/projects/openttd_vs90.vcproj.in
@@ -52,7 +52,7 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include"
+ AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR=\"OpenTTD\";WITH_ASSERT"
StringPooling="true"
ExceptionHandling="1"
@@ -154,7 +154,7 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
- AdditionalIncludeDirectories="..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include"
+ AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR=\"OpenTTD\""
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -254,7 +254,7 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include"
+ AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR=\"OpenTTD\";_SQ64;WITH_ASSERT"
StringPooling="true"
ExceptionHandling="1"
@@ -358,7 +358,7 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
- AdditionalIncludeDirectories="..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include"
+ AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;ENABLE_AI;WITH_PERSONAL_DIR;PERSONAL_DIR=\"OpenTTD\";_SQ64"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
diff --git a/projects/settings_vs100.vcxproj b/projects/settings_vs100.vcxproj
--- a/projects/settings_vs100.vcxproj
+++ b/projects/settings_vs100.vcxproj
@@ -1,53 +0,0 @@
-
-
-
-
- Debug
- Win32
-
-
-
- settings
- {0817F629-589E-4A3B-B81A-8647BC571E35}
- settings
-
-
-
- Makefile
-
-
-
-
-
-
-
-
-
-..\objs\settings\settings_gen.exe -o ..\objs\settings\table\settings.h -b ..\src\table\settings.h.preamble -a ..\src\table\settings.h.postamble ..\src\table\company_settings.ini ..\src\table\currency_settings.ini ..\src\table\gameopt_settings.ini ..\src\table\misc_settings.ini ..\src\table\settings.ini ..\src\table\win32_settings.ini
-
-
-
- <_ProjectFileVersion>10.0.30319.1
- ..\objs\settings\table\
- ..\objs\settings\table\
- $(SettingsCommandLine)
- $(SettingsCommandLine)
- del ..\objs\settings\table\settings.h
- ..\objs\settings\table\settings.h
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/projects/settings_vs100.vcxproj.filters b/projects/settings_vs100.vcxproj.filters
--- a/projects/settings_vs100.vcxproj.filters
+++ b/projects/settings_vs100.vcxproj.filters
@@ -1,32 +0,0 @@
-
-
-
-
- {21deca6c-8df4-4f34-9dad-17d7781cd5a0}
-
-
-
-
- INI
-
-
- INI
-
-
- INI
-
-
- INI
-
-
- INI
-
-
- INI
-
-
-
-
-
-
-
diff --git a/projects/settings_vs100.vcxproj.filters.in b/projects/settings_vs100.vcxproj.filters.in
--- a/projects/settings_vs100.vcxproj.filters.in
+++ b/projects/settings_vs100.vcxproj.filters.in
@@ -1,15 +0,0 @@
-
-
-
-
- {21deca6c-8df4-4f34-9dad-17d7781cd5a0}
-
-
-
-!!FILES!!
-
-
-
-
-
-
diff --git a/projects/settings_vs100.vcxproj.in b/projects/settings_vs100.vcxproj.in
--- a/projects/settings_vs100.vcxproj.in
+++ b/projects/settings_vs100.vcxproj.in
@@ -1,48 +0,0 @@
-
-
-
-
- Debug
- Win32
-
-
-
- settings
- {0817F629-589E-4A3B-B81A-8647BC571E35}
- settings
-
-
-
- Makefile
-
-
-
-
-
-
-
-
-
-!!FILTERS!!
-
-
-
- <_ProjectFileVersion>10.0.30319.1
- ..\objs\settings\table\
- ..\objs\settings\table\
- $(SettingsCommandLine)
- $(SettingsCommandLine)
- del ..\objs\settings\table\settings.h
- ..\objs\settings\table\settings.h
-
-
-!!FILES!!
-
-
-
-
-
-
-
-
-
diff --git a/projects/settings_vs80.vcproj b/projects/settings_vs80.vcproj
--- a/projects/settings_vs80.vcproj
+++ b/projects/settings_vs80.vcproj
@@ -1,83 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/projects/settings_vs80.vcproj.in b/projects/settings_vs80.vcproj.in
--- a/projects/settings_vs80.vcproj.in
+++ b/projects/settings_vs80.vcproj.in
@@ -1,60 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-!!FILES!!
-
-
-
-
-
-
-
-
-
diff --git a/projects/settings_vs90.vcproj b/projects/settings_vs90.vcproj
--- a/projects/settings_vs90.vcproj
+++ b/projects/settings_vs90.vcproj
@@ -1,84 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/projects/settings_vs90.vcproj.in b/projects/settings_vs90.vcproj.in
--- a/projects/settings_vs90.vcproj.in
+++ b/projects/settings_vs90.vcproj.in
@@ -1,61 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-!!FILES!!
-
-
-
-
-
-
-
-
-
diff --git a/projects/settingsgen_vs100.vcxproj b/projects/settingsgen_vs100.vcxproj
--- a/projects/settingsgen_vs100.vcxproj
+++ b/projects/settingsgen_vs100.vcxproj
@@ -1,81 +0,0 @@
-
-
-
-
- Debug
- Win32
-
-
-
- settingsgen
- {E9548DE9-F089-49B7-93A6-30BE2CC311C7}
- settings
-
-
-
- Application
- MultiByte
-
-
-
-
-
-
-
-
-
- <_ProjectFileVersion>10.0.30319.1
- ..\objs\settings\
- ..\objs\settings\
- settings_gen
-
-
-
-
-
-
-
- %(Inputs)
-
-
- MinSpace
- Size
- SETTINGSGEN;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
- All
- $(IntDir)$(TargetName).pdb
- Level3
- true
- ProgramDatabase
- MultiThreadedDebug
-
-
- $(OutDir)settings_gen.exe
- true
- false
-
-
- Console
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/projects/settingsgen_vs100.vcxproj.filters b/projects/settingsgen_vs100.vcxproj.filters
--- a/projects/settingsgen_vs100.vcxproj.filters
+++ b/projects/settingsgen_vs100.vcxproj.filters
@@ -1,32 +0,0 @@
-
-
-
-
- {a4678737-b3b3-4be5-9db1-fa6ccd164c59}
-
-
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
-
-
-
-
-
-
-
-
diff --git a/projects/settingsgen_vs80.vcproj b/projects/settingsgen_vs80.vcproj
--- a/projects/settingsgen_vs80.vcproj
+++ b/projects/settingsgen_vs80.vcproj
@@ -1,143 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/projects/settingsgen_vs90.vcproj b/projects/settingsgen_vs90.vcproj
--- a/projects/settingsgen_vs90.vcproj
+++ b/projects/settingsgen_vs90.vcproj
@@ -1,142 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/projects/version_vs100.vcxproj b/projects/version_vs100.vcxproj
--- a/projects/version_vs100.vcxproj
+++ b/projects/version_vs100.vcxproj
@@ -30,7 +30,6 @@
cscript "$(ProjectDir)/determineversion.vbs"
cscript "$(ProjectDir)/determineversion.vbs"
..\src\rev.cpp
- del ..\src\rev.cpp
@@ -39,4 +38,4 @@
-
\ No newline at end of file
+
diff --git a/source.list b/source.list
--- a/source.list
+++ b/source.list
@@ -8,13 +8,16 @@ cargopacket.cpp
cargotype.cpp
cheat.cpp
command.cpp
+command_queue.cpp
console.cpp
console_cmds.cpp
+copy_paste.cpp
crashlog.cpp
currency.cpp
date.cpp
debug.cpp
dedicated.cpp
+departures.cpp
depot.cpp
driver.cpp
economy.cpp
@@ -32,12 +35,17 @@ ground_vehicle.cpp
heightmap.cpp
highscore.cpp
hotkeys.cpp
+infrastructure.cpp
ini.cpp
-ini_load.cpp
landscape.cpp
+linkgraph/demands.cpp
+linkgraph/flowmapper.cpp
+linkgraph/linkgraph.cpp
+linkgraph/mcf.cpp
map.cpp
misc.cpp
mixer.cpp
+moving_average.cpp
music.cpp
network/network.cpp
network/network_admin.cpp
@@ -51,6 +59,7 @@ openttd.cpp
order_backup.cpp
os_timer.cpp
pbs.cpp
+programmable_signals.cpp
rail.cpp
rev.cpp
road.cpp
@@ -90,6 +99,7 @@ townname.cpp
#end
#end
#end
+trafficlight.cpp
vehicle.cpp
vehiclelist.cpp
viewport.cpp
@@ -126,6 +136,7 @@ clear_func.h
cmd_helper.h
command_func.h
command_type.h
+command_queue.h
company_base.h
company_func.h
company_gui.h
@@ -135,6 +146,7 @@ console_func.h
console_gui.h
console_internal.h
console_type.h
+copy_paste.h
crashlog.h
currency.h
date_func.h
@@ -142,6 +154,9 @@ date_gui.h
date_type.h
debug.h
video/dedicated_v.h
+departures_func.h
+departures_gui.h
+departures_type.h
depot_base.h
depot_func.h
depot_map.h
@@ -184,14 +199,21 @@ house_type.h
industry.h
industry_type.h
industrytype.h
+infrastructure_func.h
ini_type.h
landscape.h
landscape_type.h
language.h
+linkgraph/demands.h
+linkgraph/flowmapper.h
+linkgraph/linkgraph.h
+linkgraph/linkgraph_type.h
+linkgraph/mcf.h
livery.h
map_func.h
map_type.h
mixer.h
+moving_average.h
network/network.h
network/network_admin.h
network/network_base.h
@@ -247,6 +269,7 @@ order_base.h
order_func.h
order_type.h
pbs.h
+programmable_signals.h
querystring_gui.h
rail.h
rail_gui.h
@@ -312,6 +335,9 @@ townname_type.h
track_func.h
track_type.h
train.h
+trafficlight.h
+trafficlight_func.h
+trafficlight_type.h
transparency.h
transparency_gui.h
transport_type.h
@@ -324,6 +350,7 @@ vehicle_type.h
vehiclelist.h
viewport_func.h
viewport_type.h
+watch_gui.h
water.h
waypoint_base.h
waypoint_func.h
@@ -369,6 +396,7 @@ core/geometry_type.hpp
core/math_func.cpp
core/math_func.hpp
core/mem_func.hpp
+core/multimap.hpp
core/overflowsafe_type.hpp
core/pool_func.cpp
core/pool_func.hpp
@@ -389,7 +417,9 @@ build_vehicle_gui.cpp
cheat_gui.cpp
company_gui.cpp
console_gui.cpp
+copy_paste_gui.cpp
date_gui.cpp
+departures_gui.cpp
depot_gui.cpp
dock_gui.cpp
engine_gui.cpp
@@ -412,6 +442,7 @@ news_gui.cpp
object_gui.cpp
order_gui.cpp
osk_gui.cpp
+programmable_signals_gui.cpp
rail_gui.cpp
road_gui.cpp
roadveh_gui.cpp
@@ -431,6 +462,7 @@ transparency_gui.cpp
tree_gui.cpp
vehicle_gui.cpp
viewport_gui.cpp
+watch_gui.cpp
waypoint_gui.cpp
# Widgets
@@ -483,6 +515,7 @@ saveload/gamelog_sl.cpp
saveload/group_sl.cpp
saveload/industry_sl.cpp
saveload/labelmaps_sl.cpp
+saveload/linkgraph_sl.cpp
saveload/map_sl.cpp
saveload/misc_sl.cpp
saveload/newgrf_sl.cpp
@@ -496,6 +529,7 @@ saveload/saveload.cpp
saveload/saveload.h
saveload/saveload_filter.h
saveload/saveload_internal.h
+saveload/signal_sl.cpp
saveload/signs_sl.cpp
saveload/station_sl.cpp
saveload/strings_sl.cpp
@@ -529,7 +563,7 @@ table/pricebase.h
table/railtypes.h
table/road_land.h
table/roadveh_movement.h
-../objs/settings/table/settings.h
+table/settings.h
table/sprites.h
table/station_land.h
table/strgen_tables.h
diff --git a/src/ai/api/ai_tile.hpp b/src/ai/api/ai_tile.hpp
--- a/src/ai/api/ai_tile.hpp
+++ b/src/ai/api/ai_tile.hpp
@@ -259,7 +259,7 @@ public:
* The returned height is the height of the bare tile. A possible foundation on the tile does not influence this height.
* @param tile The tile to check on.
* @pre AIMap::IsValidTile(tile).
- * @return The height of the lowest corner of the tile, ranging from 0 to 15.
+ * @return The height of the lowest corner of the tile, ranging from 0 to 15, or 0 to 255 in case of AllowMoreHeightlevels().
*/
static int32 GetMinHeight(TileIndex tile);
@@ -268,7 +268,7 @@ public:
* The returned height is the height of the bare tile. A possible foundation on the tile does not influence this height.
* @param tile The tile to check on.
* @pre AIMap::IsValidTile(tile).
- * @return The height of the highest corner of the tile, ranging from 0 to 15.
+ * @return The height of the highest corner of the tile, ranging from 0 to 15, or 0 to 255 in case of AllowMoreHeightlevels().
*/
static int32 GetMaxHeight(TileIndex tile);
@@ -278,7 +278,7 @@ public:
* @param tile The tile to check on.
* @param corner The corner to query.
* @pre AIMap::IsValidTile(tile).
- * @return The height of the lowest corner of the tile, ranging from 0 to 15.
+ * @return The height of the lowest corner of the tile, ranging from 0 to 15, or 0 to 255 in case of AllowMoreHeightlevels().
*/
static int32 GetCornerHeight(TileIndex tile, Corner corner);
diff --git a/src/aircraft.h b/src/aircraft.h
--- a/src/aircraft.h
+++ b/src/aircraft.h
@@ -15,6 +15,19 @@
#include "station_map.h"
#include "vehicle_base.h"
+/**
+ * Minimal, maximal and holding flying altitude above ground while a plane is in flight
+ * and not starting or landing, i.e. in the state SLOWTURN & NOSPDCLAMP.
+ * Under certain circumstances, the actual flying altitude is
+ * higher, because certain offsets are added.
+ */
+enum AircraftFlyingAltitude {
+ AIRCRAFT_MIN_FLYING_ALTITUDE = 120, ///< minimal flying altitude above tile.
+ AIRCRAFT_MAX_FLYING_ALTITUDE = 360, ///< maximal flying altitude above tile.
+ PLANE_HOLD_MAX_FLYING_ALTITUDE = 150, ///< holding flying altitude above tile of planes.
+ HELICOPTER_HOLD_MAX_FLYING_ALTITUDE = 184 ///< holding flying altitude above tile of helicopters. // check if disaster vehicles behave the same. ifnot make it so ...
+};
+
struct Aircraft;
/** An aircraft can be one of those types. */
@@ -25,7 +38,6 @@ enum AircraftSubType {
AIR_ROTOR = 6 ///< rotor of an helicopter
};
-
void HandleAircraftEnterHangar(Aircraft *v);
void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height);
void UpdateAirplanesOnNewStation(const Station *st);
@@ -33,14 +45,18 @@ void UpdateAircraftCache(Aircraft *v);
void AircraftLeaveHangar(Aircraft *v);
void AircraftNextAirportPos_and_Order(Aircraft *v);
+uint GetAircraftMinAltitude(int x_pos, int y_pos, int offset);
+uint GetAircraftMaxAltitude(int x_pos, int y_pos, int offset);
+uint GetAircraftHoldMaxAltitude(const Aircraft *v);
void SetAircraftPosition(Aircraft *v, int x, int y, int z);
-byte GetAircraftFlyingAltitude(const Aircraft *v);
+void FindBreakdownDestination(Aircraft *v);
/**
* Aircraft, helicopters, rotors and their shadows belong to this class.
*/
struct Aircraft : public SpecializedVehicle {
uint16 crashed_counter; ///< Timer for handling crash animations.
+ uint16 cached_max_speed;
byte pos; ///< Next desired position of the aircraft.
byte previous_pos; ///< Previous desired position of the aircraft.
StationID targetairport; ///< Airport to go to next.
@@ -49,6 +65,22 @@ struct Aircraft : public SpecializedVehi
byte number_consecutive_turns; ///< Protection to prevent the aircraft of making a lot of turns in order to reach a specific point.
byte turn_counter; ///< Ticks between each turn to prevent > 45 degree turns.
+ /**
+ * True if an only if the aircraft has touched its upper altitude limit
+ * and currently corrects its altitude. Used in order to avoid the
+ * aircraft "stairclimbing". When an aircraft starts correcting
+ * altitude it should make a rather big correction in one step.
+ */
+ bool in_max_height_correction;
+
+ /**
+ * True if an only if the aircraft has touched its lower altitude limit
+ * and currently corrects its altitude. Used in order to avoid the
+ * aircraft "stairclimbing". When an aircraft starts correcting
+ * altitude it should make a rather big correction in one step.
+ */
+ bool in_min_height_correction;
+
/** We don't want GCC to zero our struct! It already is zeroed and has an index! */
Aircraft() : SpecializedVehicleBase() {}
/** We want to 'destruct' the right class. */
diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp
--- a/src/aircraft_cmd.cpp
+++ b/src/aircraft_cmd.cpp
@@ -16,6 +16,7 @@
#include "aircraft.h"
#include "landscape.h"
#include "news_func.h"
+#include "tile_map.h"
#include "vehicle_gui.h"
#include "newgrf_engine.h"
#include "newgrf_sound.h"
@@ -35,15 +36,12 @@
#include "engine_base.h"
#include "core/random_func.hpp"
#include "core/backup_type.hpp"
+#include "infrastructure_func.h"
#include "table/strings.h"
static const uint ROTOR_Z_OFFSET = 5; ///< Z Offset between helicopter- and rotorsprite.
-static const uint PLANE_HOLDING_ALTITUDE = 150; ///< Altitude of planes in holding pattern (= lowest flight altitude).
-static const uint HELI_FLIGHT_ALTITUDE = 184; ///< Normal flight altitude of helicopters.
-
-
void Aircraft::UpdateDeltaXY(Direction direction)
{
this->x_offs = -1;
@@ -122,10 +120,15 @@ static StationID FindNearestHangar(const
const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type);
FOR_ALL_STATIONS(st) {
- if (st->owner != v->owner || !(st->facilities & FACIL_AIRPORT)) continue;
+ if (!IsInfraUsageAllowed(VEH_AIRCRAFT, v->owner, st->owner) || !(st->facilities & FACIL_AIRPORT)) continue;
const AirportFTAClass *afc = st->airport.GetFTA();
if (!st->airport.HasHangar() || (
+ /* The airport needs to have facilities for this plane type. */
+ (AircraftVehInfo(v->engine_type)->subtype & AIR_CTOL) ?
+ !(afc->flags & AirportFTAClass::AIRPLANES) :
+ !(afc->flags & AirportFTAClass::HELICOPTERS)
+ ) || (
/* don't crash the plane if we know it can't land at the airport */
(afc->flags & AirportFTAClass::SHORT_STRIP) &&
(avi->subtype & AIR_FAST) &&
@@ -143,6 +146,27 @@ static StationID FindNearestHangar(const
return index;
}
+#if 0
+/** Check if given vehicle has a goto hangar in his orders
+ * @param v vehicle to inquiry
+ * @return true if vehicle v has an airport in the schedule, that has a hangar */
+static bool HaveHangarInOrderList(Aircraft *v)
+{
+ const Order *order;
+
+ FOR_VEHICLE_ORDERS(v, order) {
+ const Station *st = Station::Get(order->station);
+ if (IsInfraUsageAllowed(VEH_AIRCRAFT, v->owner, st->owner) && (st->facilities & FACIL_AIRPORT)) {
+ /* If an airport doesn't have a hangar, skip it */
+ if (st->Airport()->nof_depots != 0)
+ return true;
+ }
+ }
+
+ return false;
+}
+#endif
+
SpriteID Aircraft::GetImage(Direction direction) const
{
uint8 spritenum = this->spritenum;
@@ -228,6 +252,14 @@ CommandCost CmdBuildAircraft(TileIndex t
const AircraftVehicleInfo *avi = &e->u.air;
const Station *st = Station::GetByTile(tile);
+ /* Engines without valid cargo should not be available */
+ if (e->GetDefaultCargoType() == CT_INVALID) return CMD_ERROR;
+
+ /* to just query the cost, it is not neccessary to have a valid tile (automation/AI) */
+ if (flags & DC_QUERY_COST) return CommandCost();
+
+ if (!IsHangarTile(tile) || !IsInfraUsageAllowed(VEH_AIRCRAFT, _current_company, GetTileOwner(tile))) return CMD_ERROR;
+
/* Prevent building aircraft types at places which can't handle them */
if (!CanVehicleUseStation(e->index, st)) return CMD_ERROR;
@@ -267,6 +299,7 @@ CommandCost CmdBuildAircraft(TileIndex t
v->name = NULL;
v->last_station_visited = INVALID_STATION;
+ v->last_loading_station = INVALID_STATION;
v->acceleration = avi->acceleration;
v->engine_type = e->index;
@@ -280,6 +313,9 @@ CommandCost CmdBuildAircraft(TileIndex t
v->reliability = e->reliability;
v->reliability_spd_dec = e->reliability_spd_dec;
+ /* Higher speed means higher breakdown chance. */
+ /* To somewhat compensate for the fact that fast aircraft spend less time in the air. */
+ v->breakdown_chance = Clamp(64 + (AircraftVehInfo(v->engine_type)->max_speed >> 3), 0, 255);
v->max_age = e->GetLifeLengthInDays();
_new_vehicle_id = v->index;
@@ -289,6 +325,8 @@ CommandCost CmdBuildAircraft(TileIndex t
v->state = HANGAR;
v->previous_pos = v->pos;
v->targetairport = GetStationIndex(tile);
+ v->in_min_height_correction = false;
+ v->in_max_height_correction = false;
v->SetNext(u);
v->service_interval = Company::Get(_current_company)->settings.vehicle.servint_aircraft;
@@ -341,7 +379,6 @@ CommandCost CmdBuildAircraft(TileIndex t
return CommandCost();
}
-
bool Aircraft::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse)
{
const Station *st = GetTargetAirportIfValid(this);
@@ -599,12 +636,14 @@ static int UpdateAircraftSpeed(Aircraft
spd = min(v->cur_speed + (spd >> 8) + (v->subspeed < t), speed_limit);
/* adjust speed for broken vehicles */
- if (v->vehstatus & VS_AIRCRAFT_BROKEN) spd = min(spd, SPEED_LIMIT_BROKEN);
+ if (v->breakdown_ctr == 1 && v->breakdown_type == BREAKDOWN_AIRCRAFT_SPEED) spd = min(v->breakdown_severity << 3, spd);
/* updates statusbar only if speed have changed to save CPU time */
if (spd != v->cur_speed) {
v->cur_speed = spd;
- SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
+ if (_settings_client.gui.vehicle_speed) {
+ SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
+ }
}
/* Adjust distance moved by plane speed setting */
@@ -619,20 +658,22 @@ static int UpdateAircraftSpeed(Aircraft
}
/**
- * Gets the cruise altitude of an aircraft.
- * The cruise altitude is determined by the velocity of the vehicle
- * and the direction it is moving
- * @param v The vehicle. Should be an aircraft
- * @returns Altitude in pixel units
+ * Get the offset in pixels to be added to the AIRCRAFT_MIN_FLYING_ALTITUDE,
+ * AIRCRAFT_MAX_FLYING_ALTITUDE constants, in order to make collisions less probable.
+ * The offset is determined by the velocity of the vehicle and the direction it is moving.
+ *
+ * @param v The aircraft that needs an offset.
+ * @return Offset in pixels to be added to the flying altitude.
*/
-byte GetAircraftFlyingAltitude(const Aircraft *v)
+uint GetAircraftFlyingAltitudeOffset(const Aircraft *v)
{
- if (v->subtype == AIR_HELICOPTER) return HELI_FLIGHT_ALTITUDE;
+ uint offset = 0;
- /* Make sure Aircraft fly no lower so that they don't conduct
- * CFITs (controlled flight into terrain)
- */
- byte base_altitude = PLANE_HOLDING_ALTITUDE;
+ if (v->subtype == AIR_HELICOPTER) {
+ offset = HELICOPTER_HOLD_MAX_FLYING_ALTITUDE - PLANE_HOLD_MAX_FLYING_ALTITUDE;
+ } else {
+ offset = 0;
+ }
/* Make sure eastbound and westbound planes do not "crash" into each
* other by providing them with vertical seperation
@@ -642,16 +683,93 @@ byte GetAircraftFlyingAltitude(const Air
case DIR_NE:
case DIR_E:
case DIR_SE:
- base_altitude += 10;
+ offset += 10;
break;
default: break;
}
/* Make faster planes fly higher so that they can overtake slower ones */
- base_altitude += min(20 * (v->vcache.cached_max_speed / 200), 90);
+ offset += min(20 * (v->vcache.cached_max_speed / 200), 90);
+ return offset;
+}
- return base_altitude;
+/**
+ * Get the tile height below the aircraft.
+ * This function is needed because aircraft can leave the mapborders.
+ * The game would crash if an aircraft leaves the northeast or southeast border.
+ * Just for completeness we check all four map edges.
+ *
+ * @param x_pos x position of the aircraft's shadow on the map.
+ * @param y_pos y position of the aircraft's shadow on the map.
+ * @return the tileheight below the aircaft's shadow.
+ */
+uint GetTileHeightBelowAircraft(int x_pos, int y_pos)
+{
+ TileIndex tile = TileVirtXY(x_pos, y_pos);
+ uint tile_height;
+
+ /* Check for being inside the map. If not call TileHeightOutsideMap() instead of TileHeight(). */
+ if (IsInsideMM(x_pos, 0, (int)MapSizeX() * (int)TILE_SIZE)
+ && IsInsideMM(y_pos, 0, (int)MapSizeY() * (int)TILE_SIZE)) {
+ tile_height = TileHeight(tile) * TILE_HEIGHT;
+ } else {
+ tile_height = TileHeightOutsideMap(x_pos, y_pos) * TILE_HEIGHT + AIRCRAFT_MAX_FLYING_ALTITUDE;
+ }
+
+ return tile_height;
+}
+
+/**
+ * Get the height in pixels, from level 0, dependant on terrain below,
+ * at wich an aircraft should start increasing it's altitude,
+ * to prevent aircraft crashing in higher terrain ahead.
+ *
+ * @param x_pos x position of the aircraft's shadow on the map.
+ * @param y_pos y position of the aircraft's shadow on the map.
+ * @param offset offset to add to returned altitude.
+ * @return Minimal aircraft flying altitude above ground, while in normal flight, in pixels.
+ */
+uint GetAircraftMinAltitude(int x_pos, int y_pos, int offset)
+{
+ uint tile_height = GetTileHeightBelowAircraft(x_pos, y_pos);
+
+ return tile_height + AIRCRAFT_MIN_FLYING_ALTITUDE + offset;
+}
+
+/**
+ * Get the height in pixels, from level 0, dependant on terrain below,
+ * at wich an aircraft should start decreasing it's altitude,
+ * to prevent aircraft taking off to space.
+ *
+ * @param x_pos x position of the aircraft's shadow on the map.
+ * @param y_pos y position of the aircraft's shadow on the map.
+ * @param offset offset to add to returned altitude.
+ * @return Maximal aircraft flying altitude above ground, while in normal flight, in pixels.
+ */
+uint GetAircraftMaxAltitude(int x_pos, int y_pos, int offset)
+{
+ uint tile_height = GetTileHeightBelowAircraft(x_pos, y_pos);
+
+ return tile_height + AIRCRAFT_MAX_FLYING_ALTITUDE + offset;
+}
+
+/**
+ * Checks the flightpath height of the aircraft, in pixels, from level 0, dependant on terrain below,
+ * after adjusting height.
+ *
+ * @param v The aircraft that may or may not need to decrease its altitude.
+ * @return Maximal aircraft holding altitude, while in normal flight, in pixels.
+ */
+uint GetAircraftHoldMaxAltitude(const Aircraft *v)
+{
+ uint tile_height = GetTileHeightBelowAircraft(v->x_pos, v->y_pos);
+
+ if (v->subtype == AIR_HELICOPTER) {
+ return tile_height + HELICOPTER_HOLD_MAX_FLYING_ALTITUDE;
+ } else {
+ return tile_height + PLANE_HOLD_MAX_FLYING_ALTITUDE;
+ }
}
/**
@@ -666,7 +784,7 @@ byte GetAircraftFlyingAltitude(const Air
* @param v The vehicle that is approaching the airport
* @param apc The Airport Class being approached.
* @param rotation The rotation of the airport.
- * @returns The index of the entry point
+ * @return The index of the entry point
*/
static byte AircraftGetEntryPoint(const Aircraft *v, const AirportFTAClass *apc, Direction rotation)
{
@@ -743,7 +861,9 @@ static bool AircraftController(Aircraft
UpdateAircraftCache(v);
AircraftNextAirportPos_and_Order(v);
/* get aircraft back on running altitude */
- SetAircraftPosition(v, v->x_pos, v->y_pos, GetAircraftFlyingAltitude(v));
+ int new_z_pos = GetAircraftMaxAltitude(v->x_pos, v->y_pos, GetAircraftFlyingAltitudeOffset(v));
+ SetAircraftPosition(v, v->x_pos, v->y_pos, new_z_pos);
+
return false;
}
}
@@ -771,14 +891,16 @@ static bool AircraftController(Aircraft
count = UpdateAircraftSpeed(v);
if (count > 0) {
v->tile = 0;
- byte z_dest = GetAircraftFlyingAltitude(v);
+
+ uint aircraft_max_altitude = GetAircraftMaxAltitude(v->x_pos, v->y_pos, GetAircraftFlyingAltitudeOffset(v));
/* Reached altitude? */
- if (v->z_pos >= z_dest) {
+ if (v->z_pos >= (int)aircraft_max_altitude) {
v->cur_speed = 0;
return true;
}
- SetAircraftPosition(v, v->x_pos, v->y_pos, min(v->z_pos + count, z_dest));
+
+ SetAircraftPosition(v, v->x_pos, v->y_pos, min(v->z_pos + count, aircraft_max_altitude));
}
}
return false;
@@ -841,6 +963,9 @@ static bool AircraftController(Aircraft
if (!UpdateAircraftSpeed(v, SPEED_LIMIT_TAXI)) return false;
v->direction = ChangeDir(v->direction, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
+
+ DEBUG(misc, 9, "New direction: %i", (int)v->direction);
+
v->cur_speed >>= 1;
SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
@@ -928,11 +1053,63 @@ static bool AircraftController(Aircraft
uint z = v->z_pos;
if (amd.flag & AMED_TAKEOFF) {
- z = min(z + 2, GetAircraftFlyingAltitude(v));
+ uint aircraft_max_altitude = GetAircraftMaxAltitude(v->x_pos, v->y_pos, GetAircraftFlyingAltitudeOffset(v));
+
+ if (aircraft_max_altitude >= z) {
+ /* The aircraft rises or has reached its flying altitude. */
+ z = min(z + 2, GetAircraftMaxAltitude(v->x_pos, v->y_pos, GetAircraftFlyingAltitudeOffset(v)));
+ } else {
+ /* Aircraft has reached its flying altitude, but then the terrain
+ * gets lower. So, its flying altitude also decreases.
+ * We ignore this effect here, as lowering altitude during takeoff
+ * would be a bit strange. */
+ }
}
- /* Let the plane drop from normal flight altitude to holding pattern altitude */
- if ((amd.flag & AMED_HOLD) && (z > PLANE_HOLDING_ALTITUDE)) z--;
+ if ((amd.flag & AMED_SLOWTURN) && (amd.flag & AMED_NOSPDCLAMP)) {
+ /* Aircraft is in flight. We want to enforce it being somewhere
+ * between the minimum and the maximum allowed altitude. */
+ uint aircraft_min_altitude = GetAircraftMinAltitude(v->x_pos, v->y_pos, GetAircraftFlyingAltitudeOffset(v));
+ uint aircraft_max_altitude = GetAircraftMaxAltitude(v->x_pos, v->y_pos, GetAircraftFlyingAltitudeOffset(v));
+ uint aircraft_middle_altitude = aircraft_min_altitude + ((uint)(aircraft_max_altitude - aircraft_min_altitude)) / 2;
+
+ /* If those assumptions would be violated, aircrafts would behave
+ * fairly strange. */
+ assert(aircraft_min_altitude < aircraft_max_altitude);
+ assert(aircraft_min_altitude < aircraft_middle_altitude);
+ assert(aircraft_middle_altitude < aircraft_max_altitude);
+
+ if (z < aircraft_min_altitude
+ || (v->in_min_height_correction && z < aircraft_middle_altitude)) {
+ /* Rise. And don't fly into that mountain right ahead.
+ * And avoid our aircraft become a stairclimber, so if we start
+ * correcting altitude, then we stop correction not too early. */
+ v->in_min_height_correction = true;
+ z += 2;
+
+ } else if (z > aircraft_max_altitude
+ || (v->in_max_height_correction && z > aircraft_middle_altitude)) {
+ /* Fly lower. You are an aircraft, not an UFO.
+ * And again, don't stop correcting altitude too early. */
+ v->in_max_height_correction = true;
+ z--;
+
+ } else if (v->in_min_height_correction && z >= aircraft_middle_altitude) {
+ /* Now, we have corrected altitude enough. */
+ v->in_min_height_correction = false;
+
+ } else if (v->in_max_height_correction && z <= aircraft_middle_altitude) {
+ /* Now, we have corrected altitude enough. */
+ v->in_max_height_correction = false;
+ }
+ }
+
+ if (amd.flag & AMED_HOLD) {
+ uint aircraft_max_hold_altitude = GetAircraftHoldMaxAltitude(v);
+ if (z > aircraft_max_hold_altitude) {
+ z--;
+ }
+ }
if (amd.flag & AMED_LAND) {
if (st->airport.tile == INVALID_TILE) {
@@ -941,7 +1118,8 @@ static bool AircraftController(Aircraft
UpdateAircraftCache(v);
AircraftNextAirportPos_and_Order(v);
/* get aircraft back on running altitude */
- SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v));
+ int new_z_pos = GetAircraftMaxAltitude(v->x_pos, v->y_pos, GetAircraftFlyingAltitudeOffset(v));
+ SetAircraftPosition(v, gp.x, gp.y, new_z_pos);
continue;
}
@@ -956,6 +1134,9 @@ static bool AircraftController(Aircraft
if (delta >= t) {
z -= CeilDiv(z - curz, t);
}
+
+ DEBUG(misc, 9, "AMED_LAND: New z is %i", z);
+
if (z < curz) z = curz;
}
@@ -977,6 +1158,39 @@ static bool AircraftController(Aircraft
}
/**
+ * Send a broken plane that needs to visit a depot to the correct location.
+ * @param v Airplane in question.
+ */
+void FindBreakdownDestination(Aircraft *v)
+{
+ assert(v->type == VEH_AIRCRAFT && v->breakdown_ctr == 1);
+
+ DestinationID destination = INVALID_STATION;
+ if (v->breakdown_type == BREAKDOWN_AIRCRAFT_DEPOT) {
+ /* Go to a hangar, if possible at our current destination. */
+ v->FindClosestDepot(NULL, &destination, NULL);
+ } else if (v->breakdown_type == BREAKDOWN_AIRCRAFT_EM_LANDING) {
+ /* Go to the nearest airport with a hangar. */
+ destination = FindNearestHangar(v);
+ } else {
+ NOT_REACHED();
+ }
+
+ if(destination != INVALID_STATION) {
+ if(destination != v->current_order.GetDestination()) {
+ v->current_order.MakeGoToDepot(destination, ODTFB_BREAKDOWN);
+ AircraftNextAirportPos_and_Order(v);
+ } else {
+ v->current_order.MakeGoToDepot(destination, ODTFB_BREAKDOWN);
+ }
+ } else {
+ /* If no hangar was found, crash. */
+ v->targetairport = INVALID_STATION;
+ CrashAirplane(v);
+ }
+}
+
+/**
* Handle crashed aircraft \a v.
* @param v Crashed aircraft.
*/
@@ -990,7 +1204,7 @@ static bool HandleCrashedAircraft(Aircra
if (v->crashed_counter < 500 && st == NULL && ((v->crashed_counter % 3) == 0) ) {
uint z = GetSlopeZ(v->x_pos, v->y_pos);
v->z_pos -= 1;
- if (v->z_pos == z) {
+ if (v->z_pos == (int32)z) {
v->crashed_counter = 500;
v->z_pos++;
}
@@ -1051,7 +1265,8 @@ static void HandleAircraftSmoke(Aircraft
if (!(v->vehstatus & VS_AIRCRAFT_BROKEN)) return;
- if (v->cur_speed < 10) {
+ /* Breakdown-related speed limits are lifted when we are on the ground. */
+ if(v->state != FLYING && v->state != LANDING && v->breakdown_type == BREAKDOWN_AIRCRAFT_SPEED) {
v->vehstatus &= ~VS_AIRCRAFT_BROKEN;
v->breakdown_ctr = 0;
return;
@@ -1167,13 +1382,18 @@ static void MaybeCrashAirplane(Aircraft
Station *st = Station::Get(v->targetairport);
/* FIXME -- MaybeCrashAirplane -> increase crashing chances of very modern airplanes on smaller than AT_METROPOLITAN airports */
- uint32 prob = (0x4000 << _settings_game.vehicle.plane_crashes);
+ uint32 prob = (_settings_game.vehicle.improved_breakdowns && _settings_game.difficulty.vehicle_breakdowns) ?
+ 0x10000 / 10000 : 0x4000 << _settings_game.vehicle.plane_crashes;
+
if ((st->airport.GetFTA()->flags & AirportFTAClass::SHORT_STRIP) &&
(AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
!_cheats.no_jetcrash.value) {
prob /= 20;
- } else {
+ } else if (!_settings_game.vehicle.improved_breakdowns) {
prob /= 1500;
+ } else if (v->breakdown_ctr == 1 && v->breakdown_type == BREAKDOWN_AIRCRAFT_EM_LANDING) {
+ /* Airplanes that are attempting an emergency landing have a 2% chance to crash */
+ prob = 0x10000 / 50;
}
if (GB(Random(), 0, 22) > prob) return;
@@ -1195,9 +1415,9 @@ static void MaybeCrashAirplane(Aircraft
static void AircraftEntersTerminal(Aircraft *v)
{
if (v->current_order.IsType(OT_GOTO_DEPOT)) return;
+ v->last_station_visited = v->targetairport;
Station *st = Station::Get(v->targetairport);
- v->last_station_visited = v->targetairport;
/* Check if station was ever visited before */
if (!(st->had_vehicle_of_type & HVOT_AIRCRAFT)) {
@@ -1436,7 +1656,7 @@ static void AircraftEventHandler_Flying(
Station *st = Station::Get(v->targetairport);
/* runway busy or not allowed to use this airstation, circle */
- if (CanVehicleUseStation(v, st) && (st->owner == OWNER_NONE || st->owner == v->owner)) {
+ if (CanVehicleUseStation(v, st) && IsInfraUsageAllowed(VEH_AIRCRAFT, v->owner, st->owner)) {
/* {32,FLYING,NOTHING_block,37}, {32,LANDING,N,33}, {32,HELILANDING,N,41},
* if it is an airplane, look for LANDING, for helicopter HELILANDING
* it is possible to choose from multiple landing runways, so loop until a free one is found */
diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp
--- a/src/autoreplace_cmd.cpp
+++ b/src/autoreplace_cmd.cpp
@@ -119,7 +119,7 @@ static void TransferCargo(Vehicle *old_v
uint amount = min(src->cargo.Count(), dest->cargo_cap - dest->cargo.Count());
if (amount <= 0) continue;
- src->cargo.MoveTo(&dest->cargo, amount, VehicleCargoList::MTA_UNLOAD, NULL);
+ src->cargo.MoveTo(&dest->cargo, amount);
}
}
diff --git a/src/bridge.h b/src/bridge.h
--- a/src/bridge.h
+++ b/src/bridge.h
@@ -75,6 +75,8 @@ void DrawBridgeMiddle(const TileInfo *ti
CommandCost CheckBridgeAvailability(BridgeType bridge_type, uint bridge_len, DoCommandFlag flags = DC_NONE);
int CalcBridgeLenCostFactor(int x);
+BridgeType GetFastestAvailableBridgeType(uint bridge_len);
+
void ResetBridges();
#endif /* BRIDGE_H */
diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp
--- a/src/cargopacket.cpp
+++ b/src/cargopacket.cpp
@@ -10,7 +10,9 @@
/** @file cargopacket.cpp Implementation of the cargo packets. */
#include "stdafx.h"
+#include "station_base.h"
#include "core/pool_func.hpp"
+#include "core/random_func.hpp"
#include "economy_base.h"
/* Initialize the cargopacket-pool */
@@ -38,13 +40,13 @@ CargoPacket::CargoPacket()
* that, in contrary to all other pools, does not memset to 0.
*/
CargoPacket::CargoPacket(StationID source, TileIndex source_xy, uint16 count, SourceType source_type, SourceID source_id) :
- feeder_share(0),
- count(count),
- days_in_transit(0),
- source_id(source_id),
- source(source),
- source_xy(source_xy),
- loaded_at_xy(0)
+ feeder_share(0),
+ count(count),
+ days_in_transit(0),
+ source_id(source_id),
+ source(source),
+ source_xy(source_xy),
+ loaded_at_xy(0)
{
assert(count != 0);
this->source_type = source_type;
@@ -107,7 +109,7 @@ FORCEINLINE void CargoPacket::Merge(Carg
/**
* Invalidates (sets source_id to INVALID_SOURCE) all cargo packets from given source.
* @param src_type Type of source.
- * @param src Index of source.
+ * @param src Index of source.
*/
/* static */ void CargoPacket::InvalidateAllFrom(SourceType src_type, SourceID src)
{
@@ -131,15 +133,15 @@ FORCEINLINE void CargoPacket::Merge(Carg
/*
*
- * Cargo list implementation
+ * Cargo list implementation.
*
*/
/**
* Destroy the cargolist ("frees" all cargo packets).
*/
-template
-CargoList::~CargoList()
+template
+CargoList::~CargoList()
{
for (Iterator it(this->packets.begin()); it != this->packets.end(); ++it) {
delete *it;
@@ -150,8 +152,8 @@ CargoList::~CargoList()
* Empty the cargo list, but don't free the cargo packets;
* the cargo packets are cleaned by CargoPacket's CleanPool.
*/
-template
-void CargoList::OnCleanPool()
+template
+void CargoList::OnCleanPool()
{
this->packets.clear();
}
@@ -161,8 +163,8 @@ void CargoList::OnCleanPool()
* Decreases count and days_in_transit.
* @param cp Packet to be removed from cache.
*/
-template
-void CargoList::RemoveFromCache(const CargoPacket *cp)
+template
+void CargoList::RemoveFromCache(const CargoPacket *cp)
{
this->count -= cp->count;
this->cargo_days_in_transit -= cp->days_in_transit * cp->count;
@@ -173,8 +175,8 @@ void CargoList::RemoveFromCache(c
* Increases count and days_in_transit.
* @param cp New packet to be inserted.
*/
-template
-void CargoList::AddToCache(const CargoPacket *cp)
+template
+void CargoList::AddToCache(const CargoPacket *cp)
{
this->count += cp->count;
this->cargo_days_in_transit += cp->days_in_transit * cp->count;
@@ -182,27 +184,28 @@ void CargoList::AddToCache(const
/**
* Appends the given cargo packet. Tries to merge it with another one in the
- * packets list. If no fitting packet is found, appends it.
+ * packets list. if no fitting packet is found, appends it.
* @warning After appending this packet may not exist anymore!
* @note Do not use the cargo packet anymore after it has been appended to this CargoList!
- * @param cp Cargo packet to add.
- * @pre cp != NULL
+ * @param cp Cargo packet to add.
+ * @param Update_cache If false, the cache is not updated; used when loading from
+ * the reservation list.
+ * @pre cp != NULL.
*/
-template
-void CargoList::Append(CargoPacket *cp)
+void VehicleCargoList::Append(CargoPacket *cp, bool update_cache)
{
- assert(cp != NULL);
- static_cast(this)->AddToCache(cp);
+ assert(cp != NULL);
- for (List::reverse_iterator it(this->packets.rbegin()); it != this->packets.rend(); it++) {
+ if (update_cache) this->AddToCache(cp);
+ for (CargoPacketList::reverse_iterator it(this->packets.rbegin()); it != this->packets.rend(); it++) {
CargoPacket *icp = *it;
- if (Tinst::AreMergable(icp, cp) && icp->count + cp->count <= CargoPacket::MAX_COUNT) {
+ if (VehicleCargoList::AreMergable(icp, cp) && icp->count + cp->count <= CargoPacket::MAX_COUNT) {
icp->Merge(cp);
return;
}
}
- /* The packet could not be merged with another one */
+ /* The packet could not be merged with another one. */
this->packets.push_back(cp);
}
@@ -211,10 +214,10 @@ void CargoList::Append(CargoPacke
* first count cargo entities and removes the rest.
* @param max_remaining Maximum amount of entities to be in the list after the command.
*/
-template
-void CargoList::Truncate(uint max_remaining)
+template
+void CargoList::Truncate(uint max_remaining)
{
- for (Iterator it(packets.begin()); it != packets.end(); /* done during loop*/) {
+ for (Iterator it(packets.begin()); it != packets.end(); /* Done during loop. */) {
CargoPacket *cp = *it;
if (max_remaining == 0) {
/* Nothing should remain, just remove the packets. */
@@ -239,110 +242,150 @@ void CargoList::Truncate(uint max
}
/**
- * Moves the given amount of cargo to another list.
- * Depending on the value of mta the side effects of this function differ:
- * - MTA_FINAL_DELIVERY: Destroys the packets that do not originate from a specific station.
- * - MTA_CARGO_LOAD: Sets the loaded_at_xy value of the moved packets.
- * - MTA_TRANSFER: Just move without side effects.
- * - MTA_UNLOAD: Just move without side effects.
- * @param dest Destination to move the cargo to.
- * @param max_move Amount of cargo entities to move.
- * @param mta How to handle the moving (side effects).
- * @param data Depending on mta the data of this variable differs:
- * - MTA_FINAL_DELIVERY - Station ID of packet's origin not to remove.
- * - MTA_CARGO_LOAD - Station's tile index of load.
- * - MTA_TRANSFER - Unused.
- * - MTA_UNLOAD - Unused.
- * @param payment The payment helper.
- *
- * @pre mta == MTA_FINAL_DELIVERY || dest != NULL
- * @pre mta == MTA_UNLOAD || mta == MTA_CARGO_LOAD || payment != NULL
- * @return True if there are still packets that might be moved from this cargo list.
+ * Reserves a packet for later loading and adds it to the cache.
+ * @param cp Packet to be reserved.
*/
-template
-template
-bool CargoList::MoveTo(Tother_inst *dest, uint max_move, MoveToAction mta, CargoPayment *payment, uint data)
+void VehicleCargoList::Reserve(CargoPacket *cp)
{
- assert(mta == MTA_FINAL_DELIVERY || dest != NULL);
- assert(mta == MTA_UNLOAD || mta == MTA_CARGO_LOAD || payment != NULL);
-
- Iterator it(this->packets.begin());
- while (it != this->packets.end() && max_move > 0) {
- CargoPacket *cp = *it;
- if (cp->source == data && mta == MTA_FINAL_DELIVERY) {
- /* Skip cargo that originated from this station. */
- ++it;
- continue;
- }
-
- if (cp->count <= max_move) {
- /* Can move the complete packet */
- max_move -= cp->count;
- this->packets.erase(it++);
- static_cast(this)->RemoveFromCache(cp);
- switch (mta) {
- case MTA_FINAL_DELIVERY:
- payment->PayFinalDelivery(cp, cp->count);
- delete cp;
- continue; // of the loop
-
- case MTA_CARGO_LOAD:
- cp->loaded_at_xy = data;
- break;
-
- case MTA_TRANSFER:
- cp->feeder_share += payment->PayTransfer(cp, cp->count);
- break;
-
- case MTA_UNLOAD:
- break;
- }
- dest->Append(cp);
- continue;
- }
-
- /* Can move only part of the packet */
- if (mta == MTA_FINAL_DELIVERY) {
- /* Final delivery doesn't need package splitting. */
- payment->PayFinalDelivery(cp, max_move);
-
- /* Remove the delivered data from the cache */
- uint left = cp->count - max_move;
- cp->count = max_move;
- static_cast(this)->RemoveFromCache(cp);
-
- /* Final delivery payment pays the feeder share, so we have to
- * reset that so it is not 'shown' twice for partial unloads. */
- cp->feeder_share = 0;
- cp->count = left;
- } else {
- /* But... the rest needs package splitting. */
- CargoPacket *cp_new = cp->Split(max_move);
-
- /* We could not allocate a CargoPacket? Is the map that full? */
- if (cp_new == NULL) return false;
-
- static_cast(this)->RemoveFromCache(cp_new); // this reflects the changes in cp.
-
- if (mta == MTA_TRANSFER) {
- /* Add the feeder share before inserting in dest. */
- cp_new->feeder_share += payment->PayTransfer(cp_new, max_move);
- } else if (mta == MTA_CARGO_LOAD) {
- cp_new->loaded_at_xy = data;
- }
-
- dest->Append(cp_new);
- }
-
- max_move = 0;
- }
-
- return it != packets.end();
+ assert(cp != NULL);
+ this->AddToCache(cp);
+ this->reserved_count += cp->count;
+ this->reserved.push_back(cp);
}
-/** Invalidates the cached data and rebuilds it. */
-template
-void CargoList::InvalidateCache()
+/**
+ * Returns all reserved cargo to the station and removes it from the cache.
+ * @param ID of next the station the cargo wants to go next.
+ * @param dest Station the cargo is returned to.
+ */
+void VehicleCargoList::Unreserve(StationID next, StationCargoList *dest)
+{
+ Iterator it(this->reserved.begin());
+ while (it != this->reserved.end()) {
+ CargoPacket *cp = *it;
+ this->RemoveFromCache(cp);
+ this->reserved_count -= cp->count;
+ dest->Append(next, cp);
+ this->reserved.erase(it++);
+ }
+}
+
+/**
+ * Load packets from the reservation list.
+ * @params max_move Number of cargo to load.
+ * @return Amount of cargo actually loaded.
+ */
+uint VehicleCargoList::LoadReserved(uint max_move)
+{
+ uint orig_max = max_move;
+ Iterator it(this->reserved.begin());
+ while (it != this->reserved.end() && max_move > 0) {
+ CargoPacket *cp = *it;
+ if (cp->count <= max_move) {
+ /* Can move the complete packet. */
+ max_move -= cp->count;
+ this->reserved.erase(it++);
+ this->reserved_count -= cp->count;
+ this->Append(cp, false);
+ } else if (CargoPacket::CanAllocateItem()) {
+ cp->count -= max_move;
+ CargoPacket *cp_new = new CargoPacket(max_move, cp->days_in_transit, cp->source, cp->source_xy, cp->loaded_at_xy, 0, cp->source_type, cp->source_id);
+ this->Append(cp_new, false);
+ this->reserved_count -= max_move;
+ max_move = 0;
+ }
+ }
+ return orig_max - max_move;
+}
+
+/**
+ * Move a single packet or part of it from this list to a vehicle and increment
+ * the given iterator.
+ * @param dest Vehicle cargo list to move to.
+ * @param it Iterator pointing to the packet.
+ * @param cap Maximum amount of cargo to be moved.
+ * @param load_place New loaded_at for the packet.
+ * @param reserve If the packet should be loaded on/reserved for the vehicle?
+ * @return Actual amount of cargo which has been moved.
+ */
+template
+uint CargoList::MovePacket(VehicleCargoList *dest, Iterator &it, uint cap, TileIndex load_place, bool reserve)
+{
+ CargoPacket *packet = this->RemovePacket(it, cap, load_place);
+ uint ret = packet->count;
+ if (reserve) {
+ dest->Reserve(packet);
+ } else {
+ dest->Append(packet);
+ }
+ return ret;
+}
+
+/**
+ * Move a single packet or part of it from this list to a station and increment
+ * the given iterator.
+ * @param dest Station cargo list to move to.
+ * @param next Next station the packet will travel to.
+ * @param it Iterator pointing to the packet.
+ * @param cap Maximum amount of cargo to be moved.
+ * @return Actual amount of cargo which has been moved.
+ */
+template
+uint CargoList::MovePacket(StationCargoList *dest, StationID next, Iterator &it, uint cap)
+{
+ CargoPacket *packet = this->RemovePacket(it, cap);
+ uint ret = packet->count;
+ dest->Append(next, packet);
+ return ret;
+}
+
+/**
+ * Remove a single packet or part of it from this list and increment the given
+ * iterator.
+ * @param it Iterator pointing to the packet.
+ * @param cap Maximum amount of cargo to be moved.
+ * @param load_place New loaded_at for the packet or INVALID_TILE if the current
+ * one shall be kept.
+ * @return Removed packet.
+ */
+template
+CargoPacket *CargoList::RemovePacket(Iterator &it, uint cap, TileIndex load_place)
+{
+ CargoPacket *packet = *it;
+ /* Load the packet if possible. */
+ if (packet->count > cap) {
+ /* Packet needs to be split. */
+ packet = packet->Split(cap);
+
+ /* We could not allocate a CargoPacket? Is the map that full?
+ * Just remove the whole packet and drop some cargo then.
+ */
+ if (packet == NULL) {
+ packet = *it;
+ uint dropped = packet->count - cap;
+ this->count -= dropped;
+ this->cargo_days_in_transit -= dropped * packet->days_in_transit;
+ packet->count = cap;
+ this->packets.erase(it++);
+ } else {
+ assert(packet->count == cap);
+ ++it;
+ }
+ } else {
+ this->packets.erase(it++);
+ }
+ static_cast(this)->RemoveFromCache(packet);
+ if (load_place != INVALID_TILE) {
+ packet->loaded_at_xy = load_place;
+ }
+ return packet;
+}
+
+/**
+ * Invalidates the cached data and rebuilds it.
+ */
+template
+void CargoList::InvalidateCache()
{
this->count = 0;
this->cargo_days_in_transit = 0;
@@ -353,6 +396,273 @@ void CargoList::InvalidateCache()
}
/**
+ * Delete a vehicle cargo list and clear its reservation list.
+ */
+VehicleCargoList::~VehicleCargoList()
+{
+ for (Iterator it(this->reserved.begin()); it != this->reserved.end(); ++it) {
+ delete *it;
+ }
+}
+
+/**
+ * Deliver a specific packet or part of it to a station and handle payment. The
+ * given iterator is incremented in the process.
+ * @param it Iterator pointing to the packet to be delivered.
+ * @param cap Maximum amount of cargo to be unloaded.
+ * @param payment Payment object to use for payment.
+ * @return Amount of cargo actually unloaded.
+ */
+uint VehicleCargoList::DeliverPacket(Iterator &it, uint cap, CargoPayment *payment)
+{
+ CargoPacket *p = *it;
+ uint unloaded = 0;
+ if (p->count <= cap) {
+ payment->PayFinalDelivery(p, p->count);
+ this->packets.erase(it++);
+ this->RemoveFromCache(p);
+ unloaded = p->count;
+ delete p;
+ } else {
+ payment->PayFinalDelivery(p, cap);
+ this->count -= cap;
+ this->cargo_days_in_transit -= cap * p->days_in_transit;
+ this->feeder_share -= p->feeder_share;
+ p->feeder_share = 0;
+ p->count -= cap;
+ unloaded = cap;
+ ++it;
+ }
+ return unloaded;
+}
+
+/**
+ * Keep a packet in the vehicle while unloading by temporarily moving it to the
+ * reservation list. The given iterator is incremented in the process.
+ * @param it Iterator pointing to the packet.
+ * @return Size of the packet.
+ */
+uint VehicleCargoList::KeepPacket(Iterator &it)
+{
+ CargoPacket *cp = *it;
+ this->reserved.push_back(cp);
+ this->reserved_count += cp->count;
+ this->packets.erase(it++);
+ return cp->count;
+}
+
+/**
+ * Transfer a packet to a station, but don't deliver it. Increment the given
+ * iterator in the process.
+ * @param it Iterator pointing to a packet in the list.
+ * @param cap Maximum amount of cargo to be transferred.
+ * @param dest Cargo list of the station the cargo should be transferred to.
+ * @param payment Payment object to be updated with the resulting transfer
+ * credits.
+ * @param next ID of the station the cargo wants to go to next.
+ * @return Amount of cargo actually moved.
+ */
+uint VehicleCargoList::TransferPacket(Iterator &it, uint cap, StationCargoList *dest, CargoPayment *payment, StationID next)
+{
+ CargoPacket *cp = this->RemovePacket(it, cap);
+ cp->feeder_share += payment->PayTransfer(cp, cp->count);
+ uint ret = cp->count;
+ dest->Append(next, cp);
+ return ret;
+}
+
+/**
+ * Determine what a cargo packet arriving at the station this list belongs to
+ * will do, using the "old", non-cargodist algorithm.
+ * @param flags Unload flags telling if the cargo is accepted and what order
+ * flags there are.
+ * @param source ID of the packets source station.
+ * @return Unload type (deliver, transfer, keep) telling what to do with the
+ * packet.
+ */
+UnloadType StationCargoList::WillUnloadOld(byte flags, StationID source)
+{
+ /* Try to unload cargo. */
+ bool move = (flags & (UL_DELIVER | UL_ACCEPTED | UL_TRANSFER)) != 0;
+ /* Try to deliver cargo if unloading. */
+ bool deliver = (flags & UL_ACCEPTED) && !(flags & UL_TRANSFER) && (source != this->station->index);
+ /* Transfer cargo if delivery was unsuccessful. */
+ bool transfer = (flags & (UL_TRANSFER | UL_DELIVER)) != 0;
+ if (move) {
+ if(deliver) {
+ return UL_DELIVER;
+ } else if (transfer) {
+ return UL_TRANSFER;
+ } else {
+ /* This case is for (non-)delivery to the source station without special flags.
+ * Like the code in MoveTo did, we keep the packet in this case.
+ */
+ return UL_KEEP;
+ }
+ } else {
+ return UL_KEEP;
+ }
+}
+
+/**
+ * Determine what a cargo packet arriving at the station this list belongs to
+ * will do, using the Cargodist algorithm.
+ * @param flags Unload flags telling if the cargo is accepted and what order
+ * flags there are.
+ * @param next The station the vehicle the cargo is coming from will
+ * visit next (or INVALID_STATION if unknown).
+ * @param via The station the cargo wants to go to next. If that is this
+ * station the cargo wants to be delivered.
+ * @param source ID of the packets source station.
+ * @return Unload type (deliver, transfer, keep) telling what to do with the
+ * packet.
+ */
+UnloadType StationCargoList::WillUnloadCargoDist(byte flags, StationID next, StationID via, StationID source)
+{
+ if (via == this->station->index) {
+ /* This is the final destination, deliver ... */
+ if (flags & UL_TRANSFER) {
+ /* .. except if explicitly told not to do so ... */
+ return UL_TRANSFER;
+ } else if (flags & UL_ACCEPTED) {
+ return UL_DELIVER;
+ } else if (flags & UL_DELIVER) {
+ /* .. or if the station suddenly doesn't accept our cargo, but we have an explicit deliver order... */
+ return UL_TRANSFER;
+ } else {
+ /* .. or else if it doesn't accept. */
+ return UL_KEEP;
+ }
+ } else {
+ /* Packet has to travel on, find out if it can stay on board. */
+ if (flags & UL_DELIVER) {
+ /* Order overrides cargodist:
+ * play by the old loading rules here as player is interfering with cargodist.
+ * Try to deliver, as move has been forced upon us. */
+ if ((flags & UL_ACCEPTED) && !(flags & UL_TRANSFER) && source != this->station->index) {
+ return UL_DELIVER;
+ } else {
+ /* Transfer cargo, as delivering didn't work. */
+ return UL_TRANSFER;
+ }
+ } else if (flags & UL_TRANSFER) {
+ /* Transfer forced. */
+ return UL_TRANSFER;
+ } else if (next == via && next != INVALID_STATION) {
+ /* Vehicle goes to the packet's next hop or has nondeterministic order: keep the packet. */
+ return UL_KEEP;
+ } else {
+ /* Vehicle goes somewhere else, transfer the packet. */
+ return UL_TRANSFER;
+ }
+ }
+}
+
+/**
+ * Swap the reserved and packets lists when starting to load cargo. Pull in the
+ * "kept" packets which were stored in the reservation list so that we don't
+ * have to iterate over them all the time.
+ * @pre this->packets.empty().
+ */
+void VehicleCargoList::SwapReserved()
+{
+ assert(this->packets.empty());
+ this->packets.swap(this->reserved);
+ this->reserved_count = 0;
+}
+
+/**
+ * Moves the given amount of cargo from a vehicle to a station.
+ * Depending on the value of flags the side effects of this function differ:
+ * - OUFB_UNLOAD_IF_POSSIBLE and dest->acceptance_pickup & GoodsEntry::GES_ACCEPTANCE:
+ * packets are accepted here and may be unloaded and/or delivered (=destroyed);
+ * If not using cargodist: all packets are unloaded and delivered.
+ * If using cargodist: only packets which have this station as final destination are unloaded and delivered.
+ * If using cargodist: other packets may or may not be unloaded, depending on next_station.
+ * If GoodsEntry::GES_ACCEPTANCE is not set and using cargodist: packets may still be unloaded, but not delivered.
+ * - OUFB_UNLOAD: unload all packets unconditionally;
+ * If OUF_UNLOAD_IF_POSSIBLE set and OUFB_TRANSFER not set: also deliver packets (no matter if using cargodist).
+ * - OUFB_TRANSFER: don't deliver any packets;
+ * Overrides delivering aspect of OUFB_UNLOAD_IF_POSSIBLE.
+ * @param source Vehicle cargo list to take the cargo from.
+ * @param max_unload Maximum amount of cargo entities to move.
+ * @param flags How to handle the moving (side effects).
+ * @param next Next unloading station in the vehicle's order list.
+ * @param has_stopped Vehicle has stopped at this station before, so don't update the flow stats for kept cargo.
+ * @param payment Payment object to be updated when delivering/transferring.
+ * @return Number of cargo entities actually moved.
+ */
+uint StationCargoList::TakeFrom(VehicleCargoList *source, uint max_unload, OrderUnloadFlags order_flags, StationID next, bool has_stopped, CargoPayment *payment)
+{
+ uint remaining_unload = max_unload;
+ uint unloaded;
+ byte flags = this->GetUnloadFlags(order_flags);
+ GoodsEntry *dest = &this->station->goods[this->cargo];
+ UnloadType action;
+
+ for (VehicleCargoList::Iterator c = source->packets.begin(); c != source->packets.end() && remaining_unload > 0;) {
+ StationID cargo_source = (*c)->source;
+ FlowStatSet &flows = dest->flows[cargo_source];
+ FlowStatSet::iterator begin = flows.begin();
+ StationID via = (begin != flows.end() ? begin->Via() : INVALID_STATION);
+ if (via != INVALID_STATION) {
+ /* Use cargodist unloading. */
+ action = this->WillUnloadCargoDist(flags, next, via, cargo_source);
+ } else {
+ /* There is no plan: use normal unloading. */
+ action = WillUnloadOld(flags, cargo_source);
+ }
+
+ switch(action) {
+ case UL_DELIVER:
+ unloaded = source->DeliverPacket(c, remaining_unload, payment);
+ if (via != INVALID_STATION) {
+ if (via == this->station->index) {
+ dest->UpdateFlowStats(flows, begin, unloaded);
+ } else {
+ dest->UpdateFlowStats(flows, unloaded, this->station->index);
+ }
+ }
+ remaining_unload -= unloaded;
+ break;
+ case UL_TRANSFER:
+ /* TransferPacket may split the packet and return the transferred part. */
+ if (via == this->station->index) {
+ via = (++begin != flows.end()) ? begin->Via() : INVALID_STATION;
+ }
+ unloaded = source->TransferPacket(c, remaining_unload, this, payment, via);
+ if (via != INVALID_STATION) {
+ dest->UpdateFlowStats(flows, begin, unloaded);
+ }
+ remaining_unload -= unloaded;
+ break;
+ case UL_KEEP:
+ unloaded = source->KeepPacket(c);
+ if (via != INVALID_STATION && next != INVALID_STATION && !has_stopped) {
+ if (via == next) {
+ dest->UpdateFlowStats(flows, begin, unloaded);
+ } else {
+ dest->UpdateFlowStats(flows, unloaded, next);
+ }
+ }
+ break;
+ default:
+ NOT_REACHED();
+ }
+ }
+ return max_unload - remaining_unload;
+}
+
+/**
+ * Additionally empty the reservation list for vehicle cargo lists.
+ */
+void VehicleCargoList::OnCleanPool()
+{
+ this->reserved.clear();
+ this->Parent::OnCleanPool();
+}
+
+/**
* Update the cached values to reflect the removal of this packet.
* Decreases count, feeder share and days_in_transit.
* @param cp Packet to be removed from cache.
@@ -375,6 +685,22 @@ void VehicleCargoList::AddToCache(const
}
/**
+ * Moves the given amount of cargo to another vehicle (during autoreplace).
+ * @param dest The destination to move the cargo to.
+ * @param cap The maximum amount of cargo entities to move.
+ * @return The amount of cargo actually moved.
+ */
+uint VehicleCargoList::MoveTo(VehicleCargoList *dest, uint cap)
+{
+ uint orig_cap = cap;
+ Iterator it = packets.begin();
+ while (it != packets.end() && cap > 0) {
+ cap -= MovePacket(dest, it, cap);
+ }
+ return orig_cap - cap;
+}
+
+/**
* Ages the all cargo in this list.
*/
void VehicleCargoList::AgeCargo()
@@ -389,22 +715,184 @@ void VehicleCargoList::AgeCargo()
}
}
-/** Invalidates the cached data and rebuild it. */
+/*
+ *
+ * Station cargo list implementation.
+ *
+ */
+
+/**
+ * Build unload flags from order flags and station acceptance.
+ * @param order_flags Order flags to check for forced transfer/deliver.
+ * @return Some combination of UL_ACCEPTED, UL_DELIVER and UL_TRANSFER.
+ */
+FORCEINLINE byte StationCargoList::GetUnloadFlags(OrderUnloadFlags order_flags)
+{
+ byte flags = 0;
+ if (HasBit(this->station->goods[this->cargo].acceptance_pickup, GoodsEntry::GES_ACCEPTANCE)) {
+ flags |= UL_ACCEPTED;
+ }
+ if (order_flags & OUFB_UNLOAD) {
+ flags |= UL_DELIVER;
+ }
+ if (order_flags & OUFB_TRANSFER) {
+ flags |= UL_TRANSFER;
+ }
+ return flags;
+}
+
+/**
+ * Appends the given cargo packet to the range of packets with the same next station.
+ * @warning After appending this packet may not exist anymore!
+ * @note Do not use the cargo packet anymore after it has been appended to this CargoList!
+ * @param next Next hop.
+ * @param cp Cargo packet to add.
+ * @pre cp != NULL
+ */
+void StationCargoList::Append(StationID next, CargoPacket *cp)
+{
+ assert(cp != NULL);
+ this->AddToCache(cp);
+
+ StationCargoPacketMap::List &list = this->packets[next];
+
+ for (StationCargoPacketMap::List::reverse_iterator it(list.rbegin()); it != list.rend(); it++) {
+ CargoPacket *icp = *it;
+ if (StationCargoList::AreMergable(icp, cp) && icp->count + cp->count <= CargoPacket::MAX_COUNT) {
+ icp->Merge(cp);
+ return;
+ }
+ }
+
+ /* The packet could not be merged with another one. */
+ list.push_back(cp);
+}
+
+/**
+ * Move packets from a specific range in this list to a vehicle.
+ * @param dest Cargo list the packets will be moved to.
+ * @param cap Maximum amount of cargo to move.
+ * @param begin Begin of the range to take packets from.
+ * @param end End of the range to take packets from.
+ * @param reserve Should the packets be loaded on/reserved for the vehicle.
+ * @return Amount of cargo that has been moved.
+ */
+uint StationCargoList::MovePackets(VehicleCargoList *dest, uint cap, Iterator begin, Iterator end, bool reserve)
+{
+ uint orig_cap = cap;
+ while (begin != end && cap > 0) {
+ cap -= this->MovePacket(dest, begin, cap, this->station->xy, reserve);
+ }
+ return orig_cap - cap;
+}
+
+/**
+ * Move suitable packets from this list to a vehicle.
+ * @param dest Vehicle cargo list to move packets to.
+ * @param cap Maximum amount of cargo to be moved.
+ * @param next Next station the vehicle will stop at.
+ * @param reserve Should the packets be loaded on/reserved for the vehicle.
+ * @return Amount of cargo that has been moved.
+ */
+uint StationCargoList::MoveTo(VehicleCargoList *dest, uint cap, StationID next, bool reserve)
+{
+ uint orig_cap = cap;
+ std::pair bounds(this->packets.equal_range(next));
+ cap -= this->MovePackets(dest, cap, bounds.first, bounds.second, reserve);
+ if (next != INVALID_STATION && cap > 0) {
+ bounds = this->packets.equal_range(INVALID_STATION);
+ cap -= this->MovePackets(dest, cap, bounds.first, bounds.second, reserve);
+ }
+ return orig_cap - cap;
+}
+
+/**
+ * Route all packets with station "to" as next hop to a different place.
+ * @param to station to exclude from routing.
+ */
+void StationCargoList::RerouteStalePackets(StationID to)
+{
+ std::pair range(this->packets.equal_range(to));
+ for (Iterator it(range.first); it != range.second && it.GetKey() == to;) {
+ CargoPacket *packet = *it;
+ this->packets.erase(it++);
+ StationID next = this->station->goods[this->cargo].UpdateFlowStatsTransfer(packet->source, packet->count, this->station->index);
+ assert(next != to);
+
+ /* Legal, as insert doesn't invalidate iterators in the MultiMap, however
+ * this might insert the packet between range.first and range.second (which might be end())
+ * This is why we check for GetKey above to avoid infinite loops.
+ */
+ this->packets.Insert(next, packet);
+ }
+}
+
+/**
+ * Truncate where each destination loses roughly the same percentage of its cargo.
+ * This is done by randomizing the selection of packets to be removed. Also count
+ * the cargo by origin station.
+ * @param max_remaining Maximum amount of cargo to keep in the station.
+ * @param cargo_per_source Container for counting the cargo by origin list.
+ */
+void StationCargoList::CountAndTruncate(uint max_remaining, StationCargoAmountMap &cargo_per_source)
+{
+ uint prev_count = this->count;
+ uint loop = 0;
+ while (this->count > max_remaining) {
+ for (Iterator it(this->packets.begin()); it != this->packets.end();) {
+ CargoPacket *packet = *it;
+ if (loop == 0) cargo_per_source[packet->source] += packet->count;
+
+ if (RandomRange(prev_count) < max_remaining) {
+ ++it;
+ continue;
+ }
+
+ uint diff = this->count - max_remaining;
+ if (packet->count > diff) {
+ packet->count -= diff;
+ this->count = max_remaining;
+ this->cargo_days_in_transit -= packet->days_in_transit * diff;
+ if (loop > 0) {
+ return;
+ } else {
+ ++it;
+ }
+ } else {
+ this->packets.erase(it++);
+ this->RemoveFromCache(packet);
+ delete packet;
+ }
+ }
+ loop++;
+ }
+}
+
+/** Invalidates the cached data and rebuilds it. */
void VehicleCargoList::InvalidateCache()
{
this->feeder_share = 0;
+ this->reserved_count = 0;
this->Parent::InvalidateCache();
+ for (ConstIterator it(this->reserved.begin()); it != this->reserved.end(); it++) {
+ this->AddToCache(*it);
+ this->reserved_count += (*it)->count;
+ }
}
-/*
- * We have to instantiate everything we want to be usable.
+/**
+ * Assign the cargo list to a goods entry.
+ * @param station The station the cargo list is asigned to
+ * @param cargo The cargo the list is asigned to.
*/
-template class CargoList;
-template class CargoList;
+void StationCargoList::AssignTo(Station *station, CargoID cargo)
+{
+ assert(this->station == NULL);
+ assert(station != NULL && cargo != INVALID_CARGO);
+ this->station = station;
+ this->cargo = cargo;
+}
-/** Autoreplace Vehicle -> Vehicle 'transfer'. */
-template bool CargoList::MoveTo(VehicleCargoList *, uint max_move, MoveToAction mta, CargoPayment *payment, uint data);
-/** Cargo unloading at a station. */
-template bool CargoList::MoveTo(StationCargoList *, uint max_move, MoveToAction mta, CargoPayment *payment, uint data);
-/** Cargo loading at a station. */
-template bool CargoList::MoveTo(VehicleCargoList *, uint max_move, MoveToAction mta, CargoPayment *payment, uint data);
+/** We have to instantiate everything we want to be usable. */
+template class CargoList;
+template class CargoList;
diff --git a/src/cargopacket.h b/src/cargopacket.h
--- a/src/cargopacket.h
+++ b/src/cargopacket.h
@@ -15,8 +15,11 @@
#include "core/pool_type.hpp"
#include "economy_type.h"
#include "station_type.h"
+#include "order_type.h"
#include "cargo_type.h"
+#include "cargotype.h"
#include "vehicle_type.h"
+#include "core/multimap.hpp"
#include
/** Unique identifier for a single cargo packet. */
@@ -28,7 +31,9 @@ typedef Pool class CargoList;
+template class CargoList;
+class StationCargoList; // forward-declare, so we can use it in VehicleCargoList::Unreserve
+class VehicleCargoList; // forward-declare, so we can use it in CargoList::MovePacket
extern const struct SaveLoad *GetCargoPacketDesc();
/**
@@ -46,7 +51,7 @@ private:
TileIndex loaded_at_xy; ///< Location where this cargo has been loaded into the vehicle.
/** The CargoList caches, thus needs to know about it. */
- template friend class CargoList;
+ template friend class CargoList;
friend class VehicleCargoList;
friend class StationCargoList;
/** We want this to be saved, right? */
@@ -140,7 +145,6 @@ public:
return this->loaded_at_xy;
}
-
static void InvalidateAllFrom(SourceType src_type, SourceID src);
static void InvalidateAllFrom(StationID sid);
static void AfterLoad();
@@ -159,38 +163,46 @@ public:
*/
#define FOR_ALL_CARGOPACKETS(var) FOR_ALL_CARGOPACKETS_FROM(var, 0)
+/** Kind of actions that could be done with packets on unloading */
+enum UnloadType {
+ UL_KEEP = 0, ///< Keep cargo on vehicle.
+ UL_DELIVER = 1 << 0, ///< Deliver cargo.
+ UL_TRANSFER = 1 << 1, ///< Transfer cargo.
+ UL_ACCEPTED = 1 << 2, ///< Cargo is accepted.
+};
+
/**
* Simple collection class for a list of cargo packets.
* @tparam Tinst Actual instantation of this cargo list.
*/
-template
+template
class CargoList {
public:
- /** Container with cargo packets. */
- typedef std::list List;
- /** The iterator for our container. */
- typedef List::iterator Iterator;
- /** The const iterator for our container. */
- typedef List::const_iterator ConstIterator;
-
- /** Kind of actions that could be done with packets on move. */
- enum MoveToAction {
- MTA_FINAL_DELIVERY, ///< "Deliver" the packet to the final destination, i.e. destroy the packet.
- MTA_CARGO_LOAD, ///< Load the packet onto a vehicle, i.e. set the last loaded station ID.
- MTA_TRANSFER, ///< The cargo is moved as part of a transfer.
- MTA_UNLOAD, ///< The cargo is moved as part of a forced unload.
- };
+ /** Iterator for our container. */
+ typedef typename Tcont::iterator Iterator;
+ /** Const iterator for our container. */
+ typedef typename Tcont::const_iterator ConstIterator;
+ /** Reverse iterator for our container. */
+ typedef typename Tcont::reverse_iterator ReverseIterator;
+ /** Const reverse iterator for our container. */
+ typedef typename Tcont::const_reverse_iterator ConstReverseIterator;
protected:
- uint count; ///< Cache for the number of cargo entities.
+ uint count; ///< Cache for the number of cargo entities.
uint cargo_days_in_transit; ///< Cache for the sum of number of days in transit of each entity; comparable to man-hours.
- List packets; ///< The cargo packets in this list.
+ Tcont packets; ///< The cargo packets in this list.
void AddToCache(const CargoPacket *cp);
void RemoveFromCache(const CargoPacket *cp);
+ CargoPacket *RemovePacket(Iterator &it, uint cap, TileIndex load_place = INVALID_TILE);
+
+ uint MovePacket(StationCargoList *dest, StationID next, Iterator &it, uint cap);
+
+ uint MovePacket(VehicleCargoList *dest, Iterator &it, uint cap, TileIndex load_place = INVALID_TILE, bool reserved = false);
+
public:
/** Create the cargo list. */
CargoList() {}
@@ -203,7 +215,7 @@ public:
* Returns a pointer to the cargo packet list (so you can iterate over it etc).
* @return Pointer to the packet list.
*/
- FORCEINLINE const List *Packets() const
+ FORCEINLINE const Tcont *Packets() const
{
return &this->packets;
}
@@ -227,15 +239,6 @@ public:
}
/**
- * Returns source of the first cargo packet in this list.
- * @return The before mentioned source.
- */
- FORCEINLINE StationID Source() const
- {
- return this->Empty() ? INVALID_STATION : this->packets.front()->source;
- }
-
- /**
* Returns average number of days in transit for a cargo entity.
* @return The before mentioned number.
*/
@@ -244,35 +247,46 @@ public:
return this->count == 0 ? 0 : this->cargo_days_in_transit / this->count;
}
-
- void Append(CargoPacket *cp);
+ void Append(CargoPacket *cp, bool update_cache = true);
void Truncate(uint max_remaining);
- template
- bool MoveTo(Tother_inst *dest, uint count, MoveToAction mta, CargoPayment *payment, uint data = 0);
-
void InvalidateCache();
};
+typedef std::list CargoPacketList;
+
/**
* CargoList that is used for vehicles.
*/
-class VehicleCargoList : public CargoList {
+class VehicleCargoList : public CargoList {
protected:
+
+ uint TransferPacket(Iterator &c, uint remaining_unload, StationCargoList *dest, CargoPayment *payment, StationID next);
+ uint DeliverPacket(Iterator &c, uint remaining_unload, CargoPayment *payment);
+ uint KeepPacket(Iterator &c);
+
/** The (direct) parent of this class. */
- typedef CargoList Parent;
+ typedef CargoList Parent;
- Money feeder_share; ///< Cache for the feeder share.
+ CargoPacketList reserved; ///< Packets reserved for unloading in this list.
+ Money feeder_share; ///< Cache for the feeder share.
+ uint reserved_count; ///< Cache for the number of reserved cargo entities.
void AddToCache(const CargoPacket *cp);
void RemoveFromCache(const CargoPacket *cp);
public:
- /** The super class ought to know what it's doing. */
- friend class CargoList;
+ /** The station cargo list needs to control the unloading. */
+ friend class StationCargoList;
+ /** The super class ought to know what it's doing */
+ friend class CargoList;
/** The vehicles have a cargo list (and we want that saved). */
friend const struct SaveLoad *GetVehicleDescription(VehicleType vt);
+ ~VehicleCargoList();
+
+ void OnCleanPool();
+
/**
* Returns total sum of the feeder share for all packets.
* @return The before mentioned number.
@@ -282,10 +296,68 @@ public:
return this->feeder_share;
}
+ void Append(CargoPacket *cp, bool update_cache = true);
+
+ /**
+ * Returns sum of cargo on board the vehicle (ie not only
+ * reserved).
+ * @return Cargo on board the vehicle.
+ */
+ FORCEINLINE uint OnboardCount() const
+ {
+ return this->count - this->reserved_count;
+ }
+
+ /**
+ * Returns sum of cargo reserved for the vehicle.
+ * @return Cargo reserved for the vehicle.
+ */
+ FORCEINLINE uint ReservedCount() const
+ {
+ return this->reserved_count;
+ }
+
+ /**
+ * Returns a pointer to the reserved cargo list.
+ * @return Pointer to the reserved list.
+ */
+ FORCEINLINE const CargoPacketList *Reserved() const
+ {
+ return &this->reserved;
+ }
+
+ /**
+ * Returns source of the first cargo packet in this list
+ * If the regular packets list is empty but there are packets
+ * in the reservation list it returns the source of the first
+ * reserved packet.
+ * @return The before mentioned source.
+ */
+ FORCEINLINE StationID Source() const
+ {
+ if (this->Empty()) {
+ return INVALID_STATION;
+ } else if (this->packets.empty()) {
+ return this->reserved.front()->source;
+ } else {
+ return this->packets.front()->source;
+ }
+ }
+
+ void Reserve(CargoPacket *cp);
+
+ void Unreserve(StationID next, StationCargoList *dest);
+
+ uint LoadReserved(uint count);
+
+ void SwapReserved();
+
void AgeCargo();
void InvalidateCache();
+ uint MoveTo(VehicleCargoList *dest, uint cap);
+
/**
* Are two the two CargoPackets mergeable in the context of
* a list of CargoPackets for a Vehicle?
@@ -303,16 +375,21 @@ public:
}
};
+typedef MultiMap StationCargoPacketMap;
+typedef std::map StationCargoAmountMap;
+
/**
* CargoList that is used for stations.
*/
-class StationCargoList : public CargoList {
+class StationCargoList : public CargoList {
public:
/** The super class ought to know what it's doing. */
- friend class CargoList;
+ friend class CargoList;
/** The stations, via GoodsEntry, have a CargoList. */
friend const struct SaveLoad *GetGoodsDesc();
+ StationCargoList() : station(NULL), cargo(INVALID_CARGO) {}
+
/**
* Are two the two CargoPackets mergeable in the context of
* a list of CargoPackets for a Vehicle?
@@ -327,6 +404,40 @@ public:
cp1->source_type == cp2->source_type &&
cp1->source_id == cp2->source_id;
}
+
+ uint TakeFrom(VehicleCargoList *source, uint max_unload, OrderUnloadFlags flags, StationID next_station, bool has_stopped, CargoPayment *payment);
+
+ uint MoveTo(VehicleCargoList *dest, uint cap, StationID next_station, bool reserve = false);
+
+ void Append(StationID next, CargoPacket *cp);
+
+ void RerouteStalePackets(StationID to);
+
+ void CountAndTruncate(uint max_remaining, StationCargoAmountMap &cargo_per_source);
+
+ /**
+ * Returns source of the first cargo packet in this list
+ * @return The before mentioned source
+ */
+ FORCEINLINE StationID Source() const
+ {
+ return this->Empty() ? INVALID_STATION : this->packets.begin()->second.front()->source;
+ }
+
+ void AssignTo(Station *station, CargoID cargo);
+
+ static void InvalidateAllFrom(SourceType src_type, SourceID src);
+
+protected:
+ Station *station; ///< Station this cargo list belongs to.
+ CargoID cargo; ///< Cargo type this list holds.
+
+ byte GetUnloadFlags(OrderUnloadFlags order_flags);
+
+ UnloadType WillUnloadOld(byte flags, StationID source);
+ UnloadType WillUnloadCargoDist(byte flags, StationID next_station, StationID via, StationID source);
+
+ uint MovePackets(VehicleCargoList *dest, uint cap, Iterator begin, Iterator end, bool reserve);
};
#endif /* CARGOPACKET_H */
diff --git a/src/cheat_gui.cpp b/src/cheat_gui.cpp
--- a/src/cheat_gui.cpp
+++ b/src/cheat_gui.cpp
@@ -133,6 +133,7 @@ static int32 ClickChangeDateCheat(int32
/** Available cheats. */
enum CheatNumbers {
CHT_MONEY, ///< Change amount of money.
+ CHT_DAYLENGTH_INCOME,///< Do not devide income by daylength factor
CHT_CHANGE_COMPANY, ///< Switch company.
CHT_EXTRA_DYNAMITE, ///< Dynamite anything.
CHT_CROSSINGTUNNELS, ///< Allow tunnels to cross each other.
@@ -166,6 +167,7 @@ struct CheatEntry {
*/
static const CheatEntry _cheats_ui[] = {
{SLE_INT32, STR_CHEAT_MONEY, &_money_cheat_amount, &_cheats.money.been_used, &ClickMoneyCheat },
+ {SLE_BOOL, STR_CHEAT_DAYLENGHT_INCOME,&_cheats.daylength_income.value, &_cheats.daylength_income.been_used, NULL },
{SLE_UINT8, STR_CHEAT_CHANGE_COMPANY, &_local_company, &_cheats.switch_company.been_used, &ClickChangeCompanyCheat },
{SLE_BOOL, STR_CHEAT_EXTRA_DYNAMITE, &_cheats.magic_bulldozer.value, &_cheats.magic_bulldozer.been_used, NULL },
{SLE_BOOL, STR_CHEAT_CROSSINGTUNNELS, &_cheats.crossing_tunnels.value, &_cheats.crossing_tunnels.been_used, NULL },
diff --git a/src/cheat_type.h b/src/cheat_type.h
--- a/src/cheat_type.h
+++ b/src/cheat_type.h
@@ -29,6 +29,7 @@ struct Cheats {
Cheat magic_bulldozer; ///< dynamite industries, objects
Cheat switch_company; ///< change to another company
Cheat money; ///< get rich or poor
+ Cheat daylength_income; ///< do not devide vehicle income by the daylength factor
Cheat crossing_tunnels; ///< allow tunnels that cross each other
Cheat dummy1; ///< empty cheat (build while in pause mode)
Cheat no_jetcrash; ///< no jet will crash on small airports anymore
diff --git a/src/clear_func.h b/src/clear_func.h
--- a/src/clear_func.h
+++ b/src/clear_func.h
@@ -19,4 +19,7 @@ void DrawClearLandTile(const TileInfo *t
void DrawClearLandFence(const TileInfo *ti);
void TileLoopClearHelper(TileIndex tile);
+/* copy_paste_gui.cpp */
+void ClearCopyArrays(uint32 w, uint32 h);
+
#endif /* CLEAR_FUNC_H */
diff --git a/src/command.cpp b/src/command.cpp
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -27,6 +27,8 @@
#include "signal_func.h"
#include "core/backup_type.hpp"
#include "object_base.h"
+#include "window_func.h"
+#include "watch_gui.h"
#include "table/strings.h"
@@ -171,8 +173,18 @@ CommandProc CmdMoveOrder;
CommandProc CmdChangeTimetable;
CommandProc CmdSetVehicleOnTime;
CommandProc CmdAutofillTimetable;
+CommandProc CmdAutomateTimetable;
CommandProc CmdSetTimetableStart;
+CommandProc CmdInsertSignalInstruction;
+CommandProc CmdModifySignalInstruction;
+CommandProc CmdRemoveSignalInstruction;
+
+CommandProc CmdSetSignalSpeedLimit;
+
+CommandProc CmdBuildTrafficLights;
+CommandProc CmdRemoveTrafficLights;
+
#define DEF_CMD(proc, flags, type) {proc, #proc, flags, type}
/**
@@ -304,7 +316,14 @@ static const Command _command_proc_table
DEF_CMD(CmdChangeTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_CHANGE_TIMETABLE
DEF_CMD(CmdSetVehicleOnTime, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_VEHICLE_ON_TIME
DEF_CMD(CmdAutofillTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_AUTOFILL_TIMETABLE
+ DEF_CMD(CmdAutomateTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_AUTOMATE_TIMETABLE
DEF_CMD(CmdSetTimetableStart, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_TIMETABLE_START
+ DEF_CMD(CmdInsertSignalInstruction, 0, CMDT_OTHER_MANAGEMENT ), // CMD_INSERT_SIGNAL_INSTRUCTION
+ DEF_CMD(CmdModifySignalInstruction, 0, CMDT_OTHER_MANAGEMENT ), // CMD_MODIFY_SIGNAL_INSTRUCTION
+ DEF_CMD(CmdRemoveSignalInstruction, 0, CMDT_OTHER_MANAGEMENT ), // CMD_REMOVE_SIGNAL_INSTRUCTION
+ DEF_CMD(CmdSetSignalSpeedLimit, 0, CMDT_OTHER_MANAGEMENT ), // CMD_SET_SIGNAL_SPEED_LIMIT
+ DEF_CMD(CmdBuildTrafficLights, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_TRAFFICLIGHTS
+ DEF_CMD(CmdRemoveTrafficLights, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_TRAFFICLIGHTS
};
/*!
@@ -712,6 +731,16 @@ CommandCost DoCommandPInternal(TileIndex
if (c != NULL) c->last_build_coordinate = tile;
}
+ /* Send Tile Number to Watching Company Windows */
+ int watching_window = 0;
+ WatchCompany *wc;
+ wc = dynamic_cast(FindWindowById(WC_WATCH_COMPANY, watching_window));
+ while (wc!=NULL) {
+ wc->OnDoCommand( _current_company, tile );
+ watching_window++;
+ wc = dynamic_cast(FindWindowById(WC_WATCH_COMPANY, watching_window));
+ }
+
SubtractMoneyFromCompany(res2);
/* update signals if needed */
diff --git a/src/command_queue.cpp b/src/command_queue.cpp
new file mode 100644
--- /dev/null
+++ b/src/command_queue.cpp
@@ -0,0 +1,77 @@
+/* $Id: command_queue.cpp 4998 2006-05-30 16:15:17Z Frostregen $ */
+
+#include "stdafx.h"
+#include "tile_type.h"
+#include "command_type.h"
+#include "command_func.h"
+#include "debug.h"
+#include "copy_paste.h"
+#include "command_queue.h"
+#include "settings_type.h"
+#include "gfx_func.h"
+#include "date_func.h"
+
+CopyPasteCommandQueue::~CopyPasteCommandQueue()
+{
+ this->ClearCopyPasteCommandQueue();
+}
+
+/** Enqueue the given command.
+ * May be executed later by calling ExecuteNextCommand()
+ */
+void CopyPasteCommandQueue::CopyPasteQueueCommand(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd)
+{
+ CommandContainer *cc = new CommandContainer;
+
+ cc->tile = tile;
+ cc->p1 = p1;
+ cc->p2 = p2;
+ cc->callback = callback;
+ cc->cmd = cmd;
+
+ /* add it to the queue */
+ this->queue.push(cc);
+}
+
+/** Executes the next queued command, or does nothing if queue is emtpy
+ * Since DoCommandP checks for _shift_pressed,
+ * we have to store, unset und restore it.
+ */
+void CopyPasteCommandQueue::ExecuteNextCommand()
+{
+ /* Check if queue is not empty */
+ if (!this->queue.empty()) {
+ /* backup and unset _shift_pressed */
+ bool temp_shift_pressed = _shift_pressed;
+ _shift_pressed = false;
+ /* Get the command and execute it */
+ DoCommandP(this->queue.front());
+ /* restore _shift_pressed */
+ _shift_pressed = temp_shift_pressed;
+ /* delete this commandcontainer */
+ {
+ CommandContainer *cc = this->queue.front();
+ this->queue.pop();
+ delete cc;
+ }
+ }
+}
+
+/** Clears the CopyPasteCommandQueue
+ */
+void CopyPasteCommandQueue::ClearCopyPasteCommandQueue()
+{
+ while (!this->queue.empty()) {
+ this->queue.pop();
+ }
+}
+
+void CallCopyPasteCommandQueueTick()
+{
+ /* Process the command_queue */
+ if (_settings_client.gui.cp_paste_speed < 255) {
+ if ((_tick_counter % _settings_client.gui.cp_paste_speed) == 0) {
+ _copy_paste_command_queue.ExecuteNextCommand();
+ }
+ }
+}
diff --git a/src/command_queue.h b/src/command_queue.h
new file mode 100644
--- /dev/null
+++ b/src/command_queue.h
@@ -0,0 +1,28 @@
+/* $Id: command_queue.h 4998 2006-05-30 16:13:41Z Frostregen $ */
+
+#ifndef COMMAND_QUEUE_H
+#define COMMAND_QUEUE_H
+
+#include "map_type.h"
+#include "command_type.h"
+#include "settings_type.h"
+#include
+
+class CopyPasteCommandQueue {
+private:
+ std::queue queue;
+
+public:
+ ~CopyPasteCommandQueue();
+
+ void ClearCopyPasteCommandQueue(); ///< Clears the CommandQueue
+
+ void CopyPasteQueueCommand(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd); ///< Enqueue the given command.
+ void ExecuteNextCommand(); ///< Executes the next queued command, or does nothing if queue is emtpy
+};
+
+extern CopyPasteCommandQueue _copy_paste_command_queue;
+
+void CallCopyPasteCommandQueueTick();
+
+#endif /* COMMAND_QUEUE_H */
diff --git a/src/command_type.h b/src/command_type.h
--- a/src/command_type.h
+++ b/src/command_type.h
@@ -268,8 +268,18 @@ enum Commands {
CMD_CHANGE_TIMETABLE, ///< change the timetable for a vehicle
CMD_SET_VEHICLE_ON_TIME, ///< set the vehicle on time feature (timetable)
CMD_AUTOFILL_TIMETABLE, ///< autofill the timetable
+ CMD_AUTOMATE_TIMETABLE, ///< automate the timetable
CMD_SET_TIMETABLE_START, ///< set the date that a timetable should start
+ CMD_INSERT_SIGNAL_INSTRUCTION, ///< insert a signal instruction
+ CMD_MODIFY_SIGNAL_INSTRUCTION, ///< modifies a signal instruction
+ CMD_REMOVE_SIGNAL_INSTRUCTION, ///< removes a signal instruction
+
+ CMD_SET_SIGNAL_SPEED_LIMIT, ///< sets the value of a speed-signal
+
+ CMD_BUILD_TRAFFICLIGHTS, ///< place traffic lights on a road crossing
+ CMD_REMOVE_TRAFFICLIGHTS, ///< remove traffic lights
+
CMD_END ///< Must ALWAYS be on the end of this list!! (period)
};
diff --git a/src/company_base.h b/src/company_base.h
--- a/src/company_base.h
+++ b/src/company_base.h
@@ -20,6 +20,8 @@
#include "economy_type.h"
#include "tile_type.h"
#include "settings_type.h"
+#include "command_type.h"
+#include "table/strings.h"
struct CompanyEconomyEntry {
Money income;
@@ -106,6 +108,13 @@ struct Company : CompanyPool::PoolItem<&
CompanySettings settings; ///< settings specific for each company
uint16 *num_engines; ///< caches the number of engines of each type the company owns (no need to save this)
+ uint32 road_infrastructure[ROADTYPE_END]; ///< NOSAVE: Count of company owned track bits for each road type.
+ uint32 signal_infrastructure; ///< NOSAVE: Count of company owned signals.
+ uint32 rail_infrastructure[RAILTYPE_END]; ///< NOSAVE: Count of company owned track bits for each rail type.
+ uint32 water_infrastructure; ///< NOSAVE: Count of company owned track bits for canals.
+ uint32 station_infrastructure; ///< NOSAVE: Count of company owned station tiles.
+ uint32 airport_infrastructure; ///< NOSAVE: Count of company owned airports.
+
/**
* Is this company a valid company, controlled by the computer (a NoAI program)?
* @param index Index in the pool.
@@ -144,6 +153,30 @@ struct Company : CompanyPool::PoolItem<&
static void PostDestructor(size_t index);
};
+struct CompanyProfile {
+ char president_name[MAX_LENGTH_PRESIDENT_NAME_CHARS];
+ char company_name[MAX_LENGTH_COMPANY_NAME_CHARS];
+ CompanyManagerFace face;
+ Livery livery[LS_END];
+
+ StringID error_id;
+
+ CompanyProfile()
+ {
+ this->error_id = STR_NULL;
+ }
+
+ CompanyProfile(StringID err)
+ {
+ this->error_id = err;
+ }
+};
+
+CompanyProfile GetCompanyProfile (const Company&);
+StringID SetCompanyProfile (const CompanyProfile&);
+StringID CompanyLoadProfile(CompanyProfile&);
+StringID CompanySaveProfile(const CompanyProfile&);
+
#define FOR_ALL_COMPANIES_FROM(var, start) FOR_ALL_ITEMS_FROM(Company, company_index, var, start)
#define FOR_ALL_COMPANIES(var) FOR_ALL_COMPANIES_FROM(var, 0)
diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp
--- a/src/company_cmd.cpp
+++ b/src/company_cmd.cpp
@@ -63,6 +63,7 @@ Company::Company(uint16 name_1, bool is_
for (uint j = 0; j < 4; j++) this->share_owners[j] = COMPANY_SPECTATOR;
InvalidateWindowData(WC_PERFORMANCE_DETAIL, 0, INVALID_COMPANY);
+ InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
}
/** Destructor. */
@@ -84,6 +85,7 @@ void Company::PostDestructor(size_t inde
InvalidateWindowData(WC_GRAPH_LEGEND, 0, (int)index);
InvalidateWindowData(WC_PERFORMANCE_DETAIL, 0, (int)index);
InvalidateWindowData(WC_COMPANY_LEAGUE, 0, 0);
+ InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
/* If the currently shown error message has this company in it, then close it. */
InvalidateWindowData(WC_ERRMSG, 0);
}
@@ -143,7 +145,8 @@ void DrawCompanyIcon(CompanyID c, int x,
* @param cmf the fact to check
* @return true if and only if the face is valid
*/
-static bool IsValidCompanyManagerFace(CompanyManagerFace cmf)
+//static bool IsValidCompanyManagerFace(CompanyManagerFace cmf) // r20689 TODO: check
+bool IsValidCompanyManagerFace(CompanyManagerFace cmf) // revert r20689 to be able to compile company_info patch
{
if (!AreCompanyManagerFaceBitsValid(cmf, CMFV_GEN_ETHN, GE_WM)) return false;
@@ -214,14 +217,16 @@ static void SubtractMoneyFromAnyCompany(
if (HasBit(1 << EXPENSES_TRAIN_INC |
1 << EXPENSES_ROADVEH_INC |
1 << EXPENSES_AIRCRAFT_INC |
- 1 << EXPENSES_SHIP_INC, cost.GetExpensesType())) {
+ 1 << EXPENSES_SHIP_INC |
+ 1 << EXPENSES_SHARING_INC, cost.GetExpensesType())) {
c->cur_economy.income -= cost.GetCost();
} else if (HasBit(1 << EXPENSES_TRAIN_RUN |
1 << EXPENSES_ROADVEH_RUN |
1 << EXPENSES_AIRCRAFT_RUN |
1 << EXPENSES_SHIP_RUN |
1 << EXPENSES_PROPERTY |
- 1 << EXPENSES_LOAN_INT, cost.GetExpensesType())) {
+ 1 << EXPENSES_LOAN_INT |
+ 1 << EXPENSES_SHARING_COST, cost.GetExpensesType())) {
c->cur_economy.expenses -= cost.GetCost();
}
@@ -567,6 +572,8 @@ Company *DoStartupNewCompany(bool is_ai,
c->num_engines = CallocT(Engine::GetPoolSize());
+ if (!is_ai) UpdateAllTownVirtCoords();
+
return c;
}
@@ -1088,6 +1095,7 @@ CommandCost CmdRenameCompany(TileIndex t
free(c->name);
c->name = reset ? NULL : strdup(text);
MarkWholeScreenDirty();
+ InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
CompanyAdminUpdate(c);
}
diff --git a/src/company_gui.cpp b/src/company_gui.cpp
--- a/src/company_gui.cpp
+++ b/src/company_gui.cpp
@@ -31,6 +31,12 @@
#include "core/geometry_func.hpp"
#include "economy_func.h"
#include "object_type.h"
+#include "rail.h"
+#include "engine_base.h"
+#include "window_func.h"
+#include "road_func.h"
+#include "water.h"
+#include "station_func.h"
#include "table/strings.h"
@@ -39,6 +45,7 @@ static const uint EXP_LINESPACE = 2;
static const uint EXP_BLOCKSPACE = 10; ///< Amount of vertical space between two blocks of numbers.
static void DoSelectCompanyManagerFace(Window *parent);
+static void ShowCompanyInfrastructure(CompanyID company);
/** Standard unsorted list of expenses. */
static ExpensesType _expenses_list_1[] = {
@@ -54,6 +61,8 @@ static ExpensesType _expenses_list_1[] =
EXPENSES_AIRCRAFT_INC,
EXPENSES_SHIP_INC,
EXPENSES_LOAN_INT,
+ EXPENSES_SHARING_INC,
+ EXPENSES_SHARING_COST,
EXPENSES_OTHER,
};
@@ -63,6 +72,7 @@ static ExpensesType _expenses_list_2[] =
EXPENSES_ROADVEH_INC,
EXPENSES_AIRCRAFT_INC,
EXPENSES_SHIP_INC,
+ EXPENSES_SHARING_INC,
INVALID_EXPENSES,
EXPENSES_TRAIN_RUN,
EXPENSES_ROADVEH_RUN,
@@ -70,6 +80,7 @@ static ExpensesType _expenses_list_2[] =
EXPENSES_SHIP_RUN,
EXPENSES_PROPERTY,
EXPENSES_LOAN_INT,
+ EXPENSES_SHARING_COST,
INVALID_EXPENSES,
EXPENSES_CONSTRUCTION,
EXPENSES_NEW_VEHICLES,
@@ -138,6 +149,7 @@ enum CompanyFinancesWindowWidgets {
CFW_SEL_BUTTONS, ///< Selection of buttons
CFW_INCREASE_LOAN, ///< Increase loan
CFW_REPAY_LOAN, ///< Decrease loan
+ CFW_INFRASTRUCTURE,///< View company infrastructure
};
/**
@@ -276,6 +288,7 @@ static const NWidgetPart _nested_company
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CFW_INCREASE_LOAN), SetFill(1, 0), SetDataTip(STR_FINANCES_BORROW_BUTTON, STR_FINANCES_BORROW_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CFW_REPAY_LOAN), SetFill(1, 0), SetDataTip(STR_FINANCES_REPAY_BUTTON, STR_FINANCES_REPAY_TOOLTIP),
+ NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CFW_INFRASTRUCTURE), SetFill(1, 0), SetDataTip(STR_FINANCES_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
EndContainer(),
EndContainer(),
};
@@ -457,6 +470,10 @@ struct CompanyFinancesWindow : Window {
case CFW_REPAY_LOAN: // repay loan
DoCommandP(0, 0, _ctrl_pressed, CMD_DECREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_REPAY_LOAN));
break;
+
+ case CFW_INFRASTRUCTURE: // show infrastructure details
+ ShowCompanyInfrastructure((CompanyID)this->window_number);
+ break;
}
}
@@ -1590,6 +1607,364 @@ static void DoSelectCompanyManagerFace(W
new SelectCompanyManagerFaceWindow(&_select_company_manager_face_desc, parent);
}
+/** Names of the widgets of the #CompanyInfrastructureWindow. */
+enum CompanyInfrastructureWindowWidgets {
+ CIW_WIDGET_CAPTION,
+ CIW_WIDGET_RAIL_DESC,
+ CIW_WIDGET_RAIL_COUNT,
+ CIW_WIDGET_ROAD_DESC,
+ CIW_WIDGET_ROAD_COUNT,
+ CIW_WIDGET_WATER_DESC,
+ CIW_WIDGET_WATER_COUNT,
+ CIW_WIDGET_STATION_DESC,
+ CIW_WIDGET_STATION_COUNT,
+ CIW_WIDGET_TOTAL_DESC,
+ CIW_WIDGET_TOTAL,
+};
+
+static const NWidgetPart _nested_company_infrastructure_widgets[] = {
+ NWidget(NWID_HORIZONTAL),
+ NWidget(WWT_CLOSEBOX, COLOUR_GREY),
+ NWidget(WWT_CAPTION, COLOUR_GREY, CIW_WIDGET_CAPTION), SetDataTip(STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+ NWidget(WWT_SHADEBOX, COLOUR_GREY),
+ NWidget(WWT_STICKYBOX, COLOUR_GREY),
+ EndContainer(),
+ NWidget(WWT_PANEL, COLOUR_GREY),
+ NWidget(NWID_VERTICAL), SetPIP(WD_FRAMERECT_TOP, 4, WD_FRAMETEXT_BOTTOM),
+ NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
+ NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_RAIL_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
+ NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_RAIL_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
+ EndContainer(),
+ NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
+ NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_ROAD_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
+ NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_ROAD_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
+ EndContainer(),
+ NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
+ NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_WATER_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
+ NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_WATER_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
+ EndContainer(),
+ NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
+ NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_STATION_DESC), SetMinimalTextLines(3, 0), SetFill(1, 0),
+ NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_STATION_COUNT), SetMinimalTextLines(3, 0), SetFill(0, 1),
+ EndContainer(),
+ NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
+ NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_TOTAL_DESC), SetFill(1, 0),
+ NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_TOTAL), SetFill(0, 1),
+ EndContainer(),
+ EndContainer(),
+ EndContainer(),
+};
+
+/**
+ * Window with detailed information about the company's infrastructure.
+ */
+struct CompanyInfrastructureWindow : Window
+{
+ RailTypes railtypes; ///< Valid railtypes.
+ RoadTypes roadtypes; ///< Valid roadtypes.
+
+ uint total_width; ///< String width of the total cost line.
+
+ CompanyInfrastructureWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
+ {
+ this->UpdateRailRoadTypes();
+
+ this->InitNested(desc, window_number);
+ this->owner = (Owner)this->window_number;
+ }
+
+ void UpdateRailRoadTypes()
+ {
+ this->railtypes = RAILTYPES_NONE;
+ this->roadtypes = ROADTYPES_ROAD; // Road is always available.
+
+ /* Find the used railtypes. */
+ Engine *e;
+ FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
+ if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
+
+ this->railtypes |= GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes;
+ }
+
+ /* Get the date introduced railtypes as well. */
+ this->railtypes = AddDateIntroducedRailTypes(this->railtypes, MAX_DAY);
+
+ /* Tram is only visible when there will be a tram. */
+ FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
+ if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
+ if (!HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue;
+
+ this->roadtypes |= ROADTYPES_TRAM;
+ break;
+ }
+ }
+
+ /** Get total infrastructure maintenance cost. */
+ Money GetTotalMaintenanceCost() const
+ {
+ const Company *c = Company::Get((CompanyID)this->window_number);
+ Money total;
+
+ for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
+ if (HasBit(this->railtypes, rt)) total += RailMaintenanceCost(rt, c->rail_infrastructure[rt]);
+ }
+ total += SignalMaintenanceCost(c->signal_infrastructure);
+
+ if (HasBit(this->roadtypes, ROADTYPE_ROAD)) total += RoadMaintenanceCost(ROADTYPE_ROAD, c->road_infrastructure[ROADTYPE_ROAD]);
+ if (HasBit(this->roadtypes, ROADTYPE_TRAM)) total += RoadMaintenanceCost(ROADTYPE_TRAM, c->road_infrastructure[ROADTYPE_TRAM]);
+
+ total += CanalMaintenanceCost(c->water_infrastructure);
+ total += StationMaintenanceCost(c->station_infrastructure);
+ total += AirportMaintenanceCost(c->index);
+
+ return total;
+ }
+
+ virtual void SetStringParameters(int widget) const
+ {
+ switch (widget) {
+ case CIW_WIDGET_CAPTION:
+ SetDParam(0, (CompanyID)this->window_number);
+ break;
+ }
+ }
+
+ virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
+ {
+ const Company *c = Company::Get((CompanyID)this->window_number);
+
+ switch (widget) {
+ case CIW_WIDGET_RAIL_DESC: {
+ uint lines = 1;
+
+ size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT).width);
+
+ for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) {
+ if (HasBit(this->railtypes, rt)) {
+ lines++;
+ SetDParam(0, GetRailTypeInfo(rt)->strings.toolbar_caption);
+ size->width = max(size->width, GetStringBoundingBox(STR_WHITE_STRING).width + WD_FRAMERECT_LEFT);
+ }
+ }
+ if (this->railtypes != RAILTYPES_NONE) {
+ lines++;
+ size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS).width + WD_FRAMERECT_LEFT);
+ }
+
+ size->height = max(size->height, lines * FONT_HEIGHT_NORMAL);
+ break;
+ }
+
+ case CIW_WIDGET_ROAD_DESC: {
+ uint lines = 1;
+
+ size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT).width);
+
+ if (HasBit(this->roadtypes, ROADTYPE_ROAD)) {
+ lines++;
+ size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD).width + WD_FRAMERECT_LEFT);
+ }
+ if (HasBit(this->roadtypes, ROADTYPE_TRAM)) {
+ lines++;
+ size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY).width + WD_FRAMERECT_LEFT);
+ }
+
+ size->height = max(size->height, lines * FONT_HEIGHT_NORMAL);
+ break;
+ }
+
+ case CIW_WIDGET_WATER_DESC:
+ size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT).width);
+ size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS).width + WD_FRAMERECT_LEFT);
+ break;
+
+ case CIW_WIDGET_STATION_DESC:
+ size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT).width);
+ size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS).width + WD_FRAMERECT_LEFT);
+ size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS).width + WD_FRAMERECT_LEFT);
+ break;
+
+ case CIW_WIDGET_RAIL_COUNT:
+ case CIW_WIDGET_ROAD_COUNT:
+ case CIW_WIDGET_WATER_COUNT:
+ case CIW_WIDGET_STATION_COUNT:
+ case CIW_WIDGET_TOTAL: {
+ /* Find the maximum count that is displayed. */
+ uint32 max_val = 1000;
+ Money max_cost = 10000;
+ for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) {
+ max_val = max(max_val, c->rail_infrastructure[rt]);
+ max_cost = max(max_cost, RailMaintenanceCost(rt, c->rail_infrastructure[rt]));
+ }
+ max_val = max(max_val, c->signal_infrastructure);
+ max_cost = max(max_cost, SignalMaintenanceCost(c->signal_infrastructure));
+ for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) {
+ max_val = max(max_val, c->road_infrastructure[rt]);
+ max_cost = max(max_cost, RoadMaintenanceCost(rt, c->road_infrastructure[rt]));
+ }
+ max_val = max(max_val, c->water_infrastructure);
+ max_cost = max(max_cost, CanalMaintenanceCost(c->water_infrastructure));
+ max_val = max(max_val, c->station_infrastructure);
+ max_cost = max(max_cost, StationMaintenanceCost(c->station_infrastructure));
+ max_val = max(max_val, c->airport_infrastructure);
+ max_cost = max(max_cost, AirportMaintenanceCost(c->index));
+
+ SetDParam(0, max_val);
+ SetDParam(1, max_cost * 12); // Convert to per year
+ size->width = max(size->width, GetStringBoundingBox(_settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA).width + 20); // Reserve some wiggle room.
+
+ if (_settings_game.economy.infrastructure_maintenance) {
+ SetDParam(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year
+ this->total_width = GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL).width + 20;
+ size->width = max(size->width, this->total_width);
+ }
+
+ /* Set height of the total line. */
+ if (widget == CIW_WIDGET_TOTAL) {
+ size->height = _settings_game.economy.infrastructure_maintenance ? max(size->height, EXP_LINESPACE + FONT_HEIGHT_NORMAL) : 0;
+ }
+ break;
+ }
+ }
+ }
+
+ virtual void DrawWidget(const Rect &r, int widget) const
+ {
+ const Company *c = Company::Get((CompanyID)this->window_number);
+ int y = r.top;
+
+ int offs_left = _current_text_dir == TD_LTR ? WD_FRAMERECT_LEFT : 0;
+ int offs_right = _current_text_dir == TD_LTR ? 0 : WD_FRAMERECT_LEFT;
+
+ switch (widget) {
+ case CIW_WIDGET_RAIL_DESC:
+ DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT);
+
+ if (this->railtypes != RAILTYPES_NONE) {
+ /* Draw name of each valid railtype. */
+ for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
+ if (HasBit(this->railtypes, rt)) {
+ SetDParam(0, GetRailTypeInfo(rt)->strings.toolbar_caption);
+ DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_WHITE_STRING);
+ }
+ }
+ DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS);
+ } else {
+ /* No valid railtype. */
+ DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
+ }
+
+ break;
+
+ case CIW_WIDGET_RAIL_COUNT:
+ /* Draw infrastructure count for each valid railtype. */
+ for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
+ if (HasBit(this->railtypes, rt)) {
+ SetDParam(0, c->rail_infrastructure[rt]);
+ SetDParam(1, RailMaintenanceCost(rt, c->rail_infrastructure[rt]) * 12); // Convert to per year
+ DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
+ }
+ }
+ if (this->railtypes != RAILTYPES_NONE) {
+ SetDParam(0, c->signal_infrastructure);
+ SetDParam(1, SignalMaintenanceCost(c->signal_infrastructure) * 12); // Convert to per year
+ DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
+ }
+ break;
+
+ case CIW_WIDGET_ROAD_DESC:
+ DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT);
+
+ if (this->roadtypes != ROADTYPES_NONE) {
+ if (HasBit(this->roadtypes, ROADTYPE_ROAD)) DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD);
+ if (HasBit(this->roadtypes, ROADTYPE_TRAM)) DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY);
+ } else {
+ /* No valid roadtypes. */
+ DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
+ }
+
+ break;
+
+ case CIW_WIDGET_ROAD_COUNT:
+ if (HasBit(this->roadtypes, ROADTYPE_ROAD)) {
+ SetDParam(0, c->road_infrastructure[ROADTYPE_ROAD]);
+ SetDParam(1, RoadMaintenanceCost(ROADTYPE_ROAD, c->road_infrastructure[ROADTYPE_ROAD]) * 12); // Convert to per year
+ DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
+ }
+ if (HasBit(this->roadtypes, ROADTYPE_TRAM)) {
+ SetDParam(0, c->road_infrastructure[ROADTYPE_TRAM]);
+ SetDParam(1, RoadMaintenanceCost(ROADTYPE_TRAM, c->road_infrastructure[ROADTYPE_TRAM]) * 12); // Convert to per year
+ DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
+ }
+ break;
+
+ case CIW_WIDGET_WATER_DESC:
+ DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT);
+ DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS);
+ break;
+
+ case CIW_WIDGET_WATER_COUNT:
+ SetDParam(0, c->water_infrastructure);
+ SetDParam(1, CanalMaintenanceCost(c->water_infrastructure) * 12); // Convert to per year
+ DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
+ break;
+
+ case CIW_WIDGET_TOTAL:
+ if (_settings_game.economy.infrastructure_maintenance) {
+ GfxFillRect(r.left, y, r.left + this->total_width, y, PC_WHITE);
+ y += EXP_LINESPACE;
+ SetDParam(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year
+ DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL);
+ }
+ break;
+
+ case CIW_WIDGET_STATION_DESC:
+ DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT);
+ DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS);
+ DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS);
+ break;
+
+ case CIW_WIDGET_STATION_COUNT:
+ SetDParam(0, c->station_infrastructure);
+ SetDParam(1, StationMaintenanceCost(c->station_infrastructure) * 12); // Convert to per year
+ DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
+ SetDParam(0, c->airport_infrastructure);
+ SetDParam(1, AirportMaintenanceCost(c->index) * 12); // Convert to per year
+ DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
+ break;
+ }
+ }
+
+ /**
+ * Some data on this window has become invalid.
+ * @param data Information about the changed data.
+ * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
+ */
+ virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
+ {
+ if (!gui_scope) return;
+
+ this->UpdateRailRoadTypes();
+ this->ReInit();
+ }
+};
+
+static const WindowDesc _company_infrastructure_desc(
+ WDP_AUTO, 0, 0,
+ WC_COMPANY_INFRASTRUCTURE, WC_NONE,
+ WDF_UNCLICK_BUTTONS,
+ _nested_company_infrastructure_widgets, lengthof(_nested_company_infrastructure_widgets)
+);
+
+/**
+ * Open the infrastructure window of a company.
+ * @param company Company to show infrastructure of.
+ */
+static void ShowCompanyInfrastructure(CompanyID company)
+{
+ if (!Company::IsValidID(company)) return;
+ AllocateWindowDescFront(&_company_infrastructure_desc, company);
+}
/** Names of the widgets of the #CompanyWindow. Keep them in the same order as in the widget array */
enum CompanyWindowWidgets {
@@ -1604,6 +1979,8 @@ enum CompanyWindowWidgets {
CW_WIDGET_DESC_VEHICLE,
CW_WIDGET_DESC_VEHICLE_COUNTS,
CW_WIDGET_DESC_COMPANY_VALUE,
+ CW_WIDGET_DESC_INFRASTRUCTURE,
+ CW_WIDGET_DESC_INFRASTRUCTURE_COUNTS,
CW_WIDGET_DESC_OWNERS,
CW_WIDGET_SELECT_BUTTONS, ///< Selection widget for the button bar.
@@ -1621,6 +1998,11 @@ enum CompanyWindowWidgets {
CW_WIDGET_SELECT_RELOCATE, ///< View/hide the 'Relocate HQ' button.
CW_WIDGET_RELOCATE_HQ,
+ CW_WIDGET_PROFILE_LOAD, ///< Load a company profile
+ CW_WIDGET_PROFILE_SAVE, ///< Save a company profile
+
+ CW_WIDGET_VIEW_INFRASTRUCTURE,
+
CW_WIDGET_HAS_PASSWORD, ///< Draw a lock when the company has a password
CW_WIDGET_SELECT_MULTIPLAYER, ///< Multiplayer selection panel.
CW_WIDGET_COMPANY_PASSWORD,
@@ -1667,10 +2049,26 @@ static const NWidgetPart _nested_company
NWidget(WWT_TEXTBTN, COLOUR_GREY, CW_WIDGET_RELOCATE_HQ), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_RELOCATE_HQ, STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS),
NWidget(NWID_SPACER), SetMinimalSize(90, 0),
EndContainer(),
+ /* Company Profile buttons */
+ NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CW_WIDGET_PROFILE_LOAD), SetFill(1, 0), SetDataTip(STR_COMPANY_PROFILE_LOAD_BUTTON, STR_COMPANY_PROFILE_LOAD_TOOLTIP),
+ NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CW_WIDGET_PROFILE_SAVE), SetFill(1, 0), SetDataTip(STR_COMPANY_PROFILE_SAVE_BUTTON, STR_COMPANY_PROFILE_SAVE_TOOLTIP),
NWidget(NWID_SPACER), SetFill(0, 1),
EndContainer(),
EndContainer(),
NWidget(WWT_TEXT, COLOUR_GREY, CW_WIDGET_DESC_COMPANY_VALUE), SetDataTip(STR_COMPANY_VIEW_COMPANY_VALUE, STR_NULL), SetFill(1, 0),
+ NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
+ NWidget(NWID_HORIZONTAL), SetPIP(0, 4, 0),
+ NWidget(NWID_VERTICAL),
+ NWidget(WWT_TEXT, COLOUR_GREY, CW_WIDGET_DESC_INFRASTRUCTURE), SetDataTip(STR_COMPANY_VIEW_INFRASTRUCTURE, STR_NULL),
+ NWidget(NWID_SPACER), SetFill(0, 1),
+ EndContainer(),
+ NWidget(WWT_EMPTY, INVALID_COLOUR, CW_WIDGET_DESC_INFRASTRUCTURE_COUNTS), SetMinimalTextLines(5, 0), SetFill(1, 0),
+ NWidget(NWID_VERTICAL),
+ NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CW_WIDGET_VIEW_INFRASTRUCTURE), SetDataTip(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
+ NWidget(NWID_SPACER), SetFill(0, 1), SetMinimalSize(90, 0),
+ EndContainer(),
+ EndContainer(),
+ EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(NWID_VERTICAL), SetPIP(5, 5, 4),
NWidget(WWT_EMPTY, INVALID_COLOUR, CW_WIDGET_DESC_OWNERS), SetMinimalTextLines(3, 0),
@@ -1800,6 +2198,10 @@ struct CompanyWindow : Window
}
if (!local) {
+ /* Not the current player, so disable profile loading/saving */
+ this->SetWidgetDisabledState(CW_WIDGET_PROFILE_LOAD, true);
+ this->SetWidgetDisabledState(CW_WIDGET_PROFILE_SAVE, true);
+
if (_settings_game.economy.allow_shares) { // Shares are allowed
/* If all shares are owned by someone (none by nobody), disable buy button */
this->SetWidgetDisabledState(CW_WIDGET_BUY_SHARE, GetAmountOwnedBy(c, INVALID_OWNER) == 0 ||
@@ -1836,6 +2238,16 @@ struct CompanyWindow : Window
}
break;
+ case CW_WIDGET_DESC_INFRASTRUCTURE_COUNTS:
+ SetDParam(0, UINT_MAX);
+ size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL).width);
+ size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD).width);
+ size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_WATER).width);
+ size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_STATION).width);
+ size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT).width);
+ size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_NONE).width);
+ break;
+
case CW_WIDGET_DESC_OWNERS: {
const Company *c2;
@@ -1866,7 +2278,7 @@ struct CompanyWindow : Window
case CW_WIDGET_FACE_TITLE:
SetDParam(0, c->index);
- DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, TC_FROMSTRING, SA_CENTER);
+ DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, TC_FROMSTRING, SA_HOR_CENTER);
break;
case CW_WIDGET_DESC_COLOUR_SCHEME_EXAMPLE:
@@ -1894,6 +2306,47 @@ struct CompanyWindow : Window
break;
}
+ case CW_WIDGET_DESC_INFRASTRUCTURE_COUNTS: {
+ uint y = r.top;
+
+ /* Collect rail and road counts. */
+ uint rail_pices = c->signal_infrastructure;
+ uint road_pieces = 0;
+ for (uint i = 0; i < lengthof(c->rail_infrastructure); i++) rail_pices += c->rail_infrastructure[i];
+ for (uint i = 0; i < lengthof(c->road_infrastructure); i++) road_pieces += c->road_infrastructure[i];
+
+ if (rail_pices == 0 && road_pieces == 0 && c->water_infrastructure == 0 && c->station_infrastructure == 0 && c->airport_infrastructure == 0) {
+ DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
+ } else {
+ if (rail_pices != 0) {
+ SetDParam(0, rail_pices);
+ DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL);
+ y += FONT_HEIGHT_NORMAL;
+ }
+ if (road_pieces != 0) {
+ SetDParam(0, road_pieces);
+ DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD);
+ y += FONT_HEIGHT_NORMAL;
+ }
+ if (c->water_infrastructure != 0) {
+ SetDParam(0, c->water_infrastructure);
+ DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_WATER);
+ y += FONT_HEIGHT_NORMAL;
+ }
+ if (c->station_infrastructure != 0) {
+ SetDParam(0, c->station_infrastructure);
+ DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_STATION);
+ y += FONT_HEIGHT_NORMAL;
+ }
+ if (c->airport_infrastructure != 0) {
+ SetDParam(0, c->airport_infrastructure);
+ DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT);
+ }
+ }
+
+ break;
+ }
+
case CW_WIDGET_DESC_OWNERS: {
const Company *c2;
uint y = r.top;
@@ -1986,6 +2439,49 @@ struct CompanyWindow : Window
this->SetWidgetDirty(CW_WIDGET_RELOCATE_HQ);
break;
+ case CW_WIDGET_PROFILE_LOAD: // When load is clicked we want to perform most of the operations from above!
+ {
+ StringID error_id;
+ CompanyProfile company_profile;
+
+ if ((byte)this->window_number != _local_company) return;
+
+ this->LowerWidget(CW_WIDGET_PROFILE_LOAD);
+ //this->SetWidgetDirty(CW_WIDGET_PROFILE_LOAD);
+
+ error_id = CompanyLoadProfile(company_profile);
+ if (error_id == STR_NULL) error_id = SetCompanyProfile(company_profile); // No error, so try setting the profile
+
+ /* If either CompanyProfileLoad or SetCompanyProfile have an error, they will be handled here */
+ if (error_id != STR_NULL) ShowErrorMessage(error_id, error_id, WL_INFO);
+
+ this->LowerWidget(CW_WIDGET_PROFILE_LOAD);
+ //this->SetWidgetDirty(CW_WIDGET_PROFILE_LOAD);
+ break;
+ }
+
+ case CW_WIDGET_PROFILE_SAVE:
+ {
+ StringID error_id;
+ CompanyProfile company_profile;
+
+ if ((byte)this->window_number != _local_company) return;
+
+ this->LowerWidget(CW_WIDGET_PROFILE_SAVE);
+
+ company_profile = GetCompanyProfile(*_company_pool.Get(_local_company));
+ error_id = CompanySaveProfile(company_profile);
+
+ if (error_id != STR_NULL) ShowErrorMessage(error_id, error_id, WL_INFO);
+
+ this->LowerWidget(CW_WIDGET_PROFILE_SAVE);
+ break;
+ }
+
+ case CW_WIDGET_VIEW_INFRASTRUCTURE:
+ ShowCompanyInfrastructure((CompanyID)this->window_number);
+ break;
+
case CW_WIDGET_BUY_SHARE:
DoCommandP(0, this->window_number, 0, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS));
break;
@@ -2079,6 +2575,16 @@ void ShowCompany(CompanyID company)
AllocateWindowDescFront(&_company_desc, company);
}
+/**
+ * Redraw all windows with company infrastructure counts.
+ * @param company The company to redraw the windows of.
+ */
+void DirtyCompanyInfrastructureWindows(CompanyID company)
+{
+ SetWindowDirty(WC_COMPANY, company);
+ SetWindowDirty(WC_COMPANY_INFRASTRUCTURE, company);
+}
+
/** widget numbers of the #BuyCompanyWindow. */
enum BuyCompanyWidgets {
BCW_CAPTION,
diff --git a/src/company_gui.h b/src/company_gui.h
--- a/src/company_gui.h
+++ b/src/company_gui.h
@@ -24,5 +24,6 @@ void ShowCompany(CompanyID company);
void InvalidateCompanyWindows(const Company *c);
void DeleteCompanyWindows(CompanyID company);
+void DirtyCompanyInfrastructureWindows(CompanyID company);
#endif /* COMPANY_GUI_H */
diff --git a/src/company_manager_face.h b/src/company_manager_face.h
--- a/src/company_manager_face.h
+++ b/src/company_manager_face.h
@@ -237,6 +237,7 @@ static inline SpriteID GetCompanyManager
return _cmf_info[cmfv].first_sprite[ge] + GB(cmf, _cmf_info[cmfv].offset, _cmf_info[cmfv].length);
}
+bool IsValidCompanyManagerFace(CompanyManagerFace cmf); // revert r20689 to be able to compile company_info patch
void DrawCompanyManagerFace(CompanyManagerFace face, int colour, int x, int y);
#endif /* COMPANY_MANAGER_FACE_H */
diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp
--- a/src/console_cmds.cpp
+++ b/src/console_cmds.cpp
@@ -1166,6 +1166,79 @@ DEF_CONSOLE_CMD(ConStartAI)
return true;
}
+DEF_CONSOLE_CMD(ConStartAllAI)
+{
+ if (argc == 0 || argc > 2) {
+ IConsoleHelp("Start all AI. Usage: 'start_ai []'");
+ IConsoleHelp("Start all AI. If is given, it starts AIs up to reach this count of running AIs.");
+ IConsoleHelp("Otherwise, the competitor setting is used.");
+ return true;
+ }
+
+ if (_game_mode != GM_NORMAL) {
+ IConsoleWarning("AIs can only be managed in a game.");
+ return true;
+ }
+
+ if (Company::GetNumItems() == CompanyPool::MAX_SIZE) {
+ IConsoleWarning("Can't start a new AI (no more free slots).");
+ return true;
+ }
+
+ if (_networking && !_network_server) {
+ IConsoleWarning("Only the server can start a new AI.");
+ return true;
+ }
+
+ if (_networking && !_settings_game.ai.ai_in_multiplayer) {
+ IConsoleWarning("AIs are not allowed in multiplayer by configuration.");
+ IConsoleWarning("Switch AI -> AI in multiplayer to True.");
+ return true;
+ }
+
+ if (!AI::CanStartNew()) {
+ IConsoleWarning("Can't start a new AI.");
+ return true;
+ }
+
+ int total_ai_count;
+ if (argc == 2) {
+ uint32 result;
+ if (GetArgumentInteger(&result, argv[1]) && result < CompanyPool::MAX_SIZE) {
+ total_ai_count = (int)result;
+ } else {
+ IConsolePrintF(CC_DEFAULT, "AI count must be an number between 1 and %d", (int)CompanyPool::MAX_SIZE - 1);
+ IConsoleWarning("Invalid AI count");
+ return true;
+ }
+ } else {
+ total_ai_count = (int)_settings_game.difficulty.max_no_competitors;
+ }
+
+ /* Total AI to start is total_ai_count - current running AIs count */
+ int new_ai_count = total_ai_count;
+ Company *c;
+ FOR_ALL_COMPANIES(c) {
+ if (Company::IsValidAiID(c->index)) {
+ new_ai_count--;
+ }
+ }
+
+ if (new_ai_count < 0) {
+ IConsolePrintF(CC_DEFAULT, "Desired a total if %d AIs. Already %d running AIs.", total_ai_count, total_ai_count - new_ai_count);
+ IConsoleWarning("There is already more AIs running than you requested for.");
+ return true;
+ }
+
+ /* Start the desired AIs */
+ IConsolePrintF(CC_DEFAULT, "Desired a total if %d AIs. Already %d running AIs, starting %d new AIs.", total_ai_count, total_ai_count - new_ai_count, new_ai_count);
+ for (int i = 0; i < new_ai_count; i++) {
+ DoCommandP(0, 1 | INVALID_COMPANY << 16, 0, CMD_COMPANY_CTRL);
+ }
+
+ return true;
+}
+
DEF_CONSOLE_CMD(ConReloadAI)
{
if (argc != 2) {
@@ -1203,6 +1276,34 @@ DEF_CONSOLE_CMD(ConReloadAI)
return true;
}
+DEF_CONSOLE_CMD(ConReloadAllAI)
+{
+ if (_game_mode != GM_NORMAL) {
+ IConsoleWarning("AIs can only be managed in a game.");
+ return true;
+ }
+
+ if (_networking && !_network_server) {
+ IConsoleWarning("Only the server can reload an AI.");
+ return true;
+ }
+
+ CompanyID company_id;
+ Company *c;
+ FOR_ALL_COMPANIES(c) {
+ company_id = c->index;
+ if (Company::IsValidID(company_id) && !Company::IsHumanID(company_id)) {
+ /* First kill the company of the AI, then start a new one. This should start the current AI again */
+ DoCommandP(0, 2 | company_id << 16, 0, CMD_COMPANY_CTRL);
+ DoCommandP(0, 1 | company_id << 16, 0, CMD_COMPANY_CTRL);
+ }
+ }
+
+ IConsolePrint(CC_DEFAULT, "All AIs reloaded.");
+
+ return true;
+}
+
DEF_CONSOLE_CMD(ConStopAI)
{
if (argc != 2) {
@@ -1239,6 +1340,33 @@ DEF_CONSOLE_CMD(ConStopAI)
return true;
}
+DEF_CONSOLE_CMD(ConStopAllAI)
+{
+ if (_game_mode != GM_NORMAL) {
+ IConsoleWarning("AIs can only be managed in a game.");
+ return true;
+ }
+
+ if (_networking && !_network_server) {
+ IConsoleWarning("Only the server can stop an AI.");
+ return true;
+ }
+
+ CompanyID company_id;
+ Company *c;
+ FOR_ALL_COMPANIES(c) {
+ company_id = c->index;
+ if (Company::IsValidID(company_id) && !Company::IsHumanID(company_id)) {
+ /* Now kill the company of the AI. */
+ DoCommandP(0, 2 | company_id << 16, 0, CMD_COMPANY_CTRL);
+ IConsolePrintF(CC_DEFAULT, "AI stopped, company %d deleted.", company_id);
+ }
+
+ }
+
+ return true;
+}
+
DEF_CONSOLE_CMD(ConRescanAI)
{
if (argc == 0) {
@@ -1899,11 +2027,14 @@ void IConsoleStdLibRegister()
#ifdef ENABLE_AI
IConsoleCmdRegister("list_ai_libs", ConListAILibs);
- IConsoleCmdRegister("list_ai", ConListAI);
- IConsoleCmdRegister("reload_ai", ConReloadAI);
- IConsoleCmdRegister("rescan_ai", ConRescanAI);
- IConsoleCmdRegister("start_ai", ConStartAI);
- IConsoleCmdRegister("stop_ai", ConStopAI);
+ IConsoleCmdRegister("list_ai", ConListAI);
+ IConsoleCmdRegister("reload_ai", ConReloadAI);
+ IConsoleCmdRegister("reload_all_ai", ConReloadAllAI);
+ IConsoleCmdRegister("rescan_ai", ConRescanAI);
+ IConsoleCmdRegister("start_ai", ConStartAI);
+ IConsoleCmdRegister("start_all_ai", ConStartAllAI);
+ IConsoleCmdRegister("stop_ai", ConStopAI);
+ IConsoleCmdRegister("stop_all_ai", ConStopAllAI);
#endif /* ENABLE_AI */
/* networking functions */
diff --git a/src/copy_paste.cpp b/src/copy_paste.cpp
new file mode 100644
--- /dev/null
+++ b/src/copy_paste.cpp
@@ -0,0 +1,1755 @@
+/* $Id: copy_paste.cpp 5998 2006-05-28 07:45:14Z Frostregen $ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "table/sprites.h"
+#include "strings_type.h"
+#include "table/strings.h"
+#include "clear_func.h"
+#include "company_func.h"
+#include "tile_type.h"
+#include "window_type.h"
+#include "gui.h"
+#include "rail_map.h"
+#include "rail_gui.h"
+#include "gfx_func.h"
+#include "settings_type.h"
+#include "sound_type.h"
+#include "sound_func.h"
+#include "command_type.h"
+#include "command_func.h"
+#include "tunnel_map.h"
+#include "bridge_map.h"
+#include "tunnelbridge_map.h"
+#include "tunnelbridge.h"
+#include "waypoint_base.h"
+#include "debug.h"
+#include "depot_map.h"
+#include "saveload/saveload.h"
+#include "window_func.h"
+#include "strings_func.h"
+#include "slope_type.h"
+#include "network/network.h"
+#include "command_queue.h"
+#include "copy_paste.h"
+#include "core/alloc_func.hpp"
+#include "core/endian_func.hpp"
+
+/* Total Space used = 8 * COPY_MAX = ?kb */
+CopyPaste _copy_paste = CopyPaste();
+
+/* Major version for saved templates */
+extern const uint32 COPYPASTE_VERSION = 1;
+
+CopyPasteCommandQueue _copy_paste_command_queue = CopyPasteCommandQueue();
+
+StringID error_message; ///< error string, used by save/load
+StringID error_extra; ///< extra error message (or NULL)
+
+CopyPaste::CopyPaste()
+{
+ m_width = 0;
+ m_height = 0;
+
+ m_copy_with_rail = true;
+ m_copy_with_road = true;
+ m_copy_with_other = false;
+ m_paste_vacant_terrain = 1;
+ m_convert_rail = true;
+ m_clear_before_build = true;
+ m_toggle_signal_direction = false;
+}
+
+void CopyPaste::AllocateMapArray(uint32 max_tiles)
+{
+ this->ClearCopyArrays();
+ m_heightmap = CallocT< int8>(max_tiles);
+ m_terrain_needed = CallocT(max_tiles);
+ m_tiletype = CallocT(max_tiles);
+ m_railroad = CallocT(max_tiles);
+ m_signals = CallocT(max_tiles);
+}
+
+CopyPaste::~CopyPaste()
+{
+ this->ClearCopyArrays();
+}
+
+/** Returns if something is currently copied
+ */
+bool CopyPaste::IsSomethingCopied()
+{
+ return !((GetWidth() == 0) || (GetHeight() == 0));
+}
+
+/** Clears the Arrays which store the copied area.
+ */
+void CopyPaste::ClearCopyArrays()
+{
+ free(m_heightmap);
+ free(m_terrain_needed);
+ free(m_tiletype);
+ free(m_railroad);
+ free(m_signals);
+ m_width = 0;
+ m_height = 0;
+}
+
+
+/**
+ * SaveLoad function for templates
+ * TODO: Compression
+ * TODO: Better error handling (use goto for block error handling)
+ **/
+SaveOrLoadResult CopyPaste::SaveLoadTemplate(const char *filename, int mode)
+{
+ FILE* fh;
+ uint32 hdr[4];
+ uint32 tlen = GetWidth() * GetHeight();
+ uint32 blen = (GetWidth() - 1) * (GetHeight() - 1);
+ uint32 index;
+ uint16 tmp16;
+ uint16* ptmp16;
+ ptmp16 = &tmp16;
+
+ uint32 version;
+
+ fh = (mode == SL_SAVE) ? fopen(filename, "wb") : fopen(filename, "rb");
+
+ switch(mode) {
+ case SL_SAVE:
+ hdr[0] = TO_BE32X('TMPL');
+ /* For now we only have a major version, but may use minor in future? */
+ hdr[1] = TO_BE32(COPYPASTE_VERSION);
+ hdr[2] = TO_BE32(GetWidth());
+ hdr[3] = TO_BE32(GetHeight());
+
+ if (fwrite(hdr, sizeof(hdr), 1, fh) != 1) {
+ fclose(fh);
+ SetError(STR_TEMPLATE_SAVE_FAILED, STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
+ return SL_ERROR;
+ }
+
+ if (fwrite(m_heightmap, sizeof(int8), tlen, fh) != tlen) goto save_error;
+ if (fwrite(m_terrain_needed, sizeof(uint8), tlen, fh) != tlen) goto save_error;
+ if (fwrite(m_tiletype, sizeof(uint8), blen, fh) != blen) goto save_error;
+ if (fwrite(m_railroad, sizeof(uint8), blen, fh) != blen) goto save_error;
+
+ for (index = 0; index < blen; index++)
+ {
+ tmp16 = TO_BE16(m_signals[index]);
+ if (fwrite(ptmp16, sizeof(uint16), 1, fh) != 1) goto save_error;
+ }
+
+ break;
+
+ case SL_LOAD:
+ if (fread(hdr, sizeof(hdr), 1, fh) != 1) goto load_error;
+ if (FROM_BE32(hdr[0]) != 'TMPL') {
+ SetError(STR_TEMPLATE_LOAD_FAILED, STR_GAME_SAVELOAD_ERROR_TEMPLATE_BROKEN);
+ return SL_ERROR;
+ }
+
+ version = FROM_BE32(hdr[1]);
+ DEBUG(sl, 1, "Loading template with version %d", version);
+
+ /* Check whether we can load this template */
+ if (version > COPYPASTE_VERSION) {
+ DEBUG(sl, 1, "Can't load template with version %d, too new!", version);
+ SetError(STR_TEMPLATE_LOAD_FAILED, STR_GAME_SAVELOAD_ERROR_TEMPLATE_TOO_NEW);
+ return SL_ERROR;
+ }
+ DEBUG(sl, 1, "Getting bounds");
+
+ {
+ uint32 width = FROM_BE32(hdr[2]);
+ uint32 height = FROM_BE32(hdr[3]);
+ AllocateMapArray(width * height);
+ SetWidth(width);
+ SetHeight(height);
+ }
+
+ tlen = GetWidth() * GetHeight();
+ blen = (GetWidth() - 1) * (GetHeight() - 1);
+
+ DEBUG(sl, 1, "Allocated arrays, loading from file");
+
+ if (fread(m_heightmap, sizeof(int8), tlen, fh) != tlen) goto load_error;
+ if (fread(m_terrain_needed, sizeof(uint8), tlen, fh) != tlen) goto load_error;
+ if (fread(m_tiletype, sizeof(uint8), blen, fh) != blen) goto load_error;
+ if (fread(m_railroad, sizeof(uint8), blen, fh) != blen) goto load_error;
+ DEBUG(sl, 1, "Reading signals");
+
+ for (index = 0; index < blen; index++) {
+ if (fread(ptmp16, sizeof(uint16), 1, fh) != 1) goto load_error;
+ m_signals[index] = FROM_BE16(tmp16);
+ }
+ SetWindowDirty(WC_COPY_PASTE, 0);
+ break;
+
+ default:
+ /* Not reached */
+ break;
+ }
+
+ fclose(fh);
+
+ return SL_OK;
+
+save_error:
+ SetError(STR_TEMPLATE_SAVE_FAILED);
+ fclose(fh);
+ return SL_ERROR;
+
+load_error:
+ SetError(STR_TEMPLATE_LOAD_FAILED);
+ fclose(fh);
+ return SL_ERROR;
+}
+
+/** Set the error string & an extra message */
+void CopyPaste::SetError(StringID message, StringID extra)
+{
+ error_message = message;
+ error_extra = extra;
+}
+
+/** Get the string representation of the error message */
+const char* CopyPaste::GetErrorString()
+{
+ //SetDParam(0, error_message);
+ SetDParam(0, error_extra);
+
+ static char str[512];
+ GetString(str, error_message, lastof(str));
+ return str;
+}
+
+/** DoCommand for Copy&Paste.
+ * If shift is pressed, a cost-estimate is displayed instead of executing the paste.
+ *
+ * If we are in multiplayer the pasting is redirected to the command-queue,
+ * which delays execution, to prevent overflowing the network connection.
+ */
+void CopyPaste::CP_DoCommand(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd)
+{
+ if (_shift_pressed) {
+ CommandCost res = DoCommand(tile, p1, p2, DC_QUERY_COST, cmd & 0xFF, "");
+ if (!res.Failed())
+ m_costs.AddCost(res);
+ }
+ else {
+#ifdef ENABLE_NETWORK
+ if (_networking) {
+ _copy_paste_command_queue.CopyPasteQueueCommand(tile, p1, p2, callback, cmd);
+ }
+ else
+#endif /* ENABLE_NETWORK */
+ DoCommandP(tile, p1, p2, cmd, callback);
+ }
+}
+
+/* *** Copy&Paste Helper functions. Mainly the same as the originals. Just without sound *** */
+
+/**
+ * @param tile The Tile to operate on
+ * @param mode true means Raise, false means Lower
+ */
+void CopyPaste::CP_RaiseLowerLand(TileIndex tile, int mode)
+{
+ CP_DoCommand(tile, 8, (uint32)mode, NULL, CMD_TERRAFORM_LAND | CMD_MSG(mode ? STR_ERROR_CAN_T_RAISE_LAND_HERE : STR_ERROR_CAN_T_LOWER_LAND_HERE));
+}
+
+void CopyPaste::CP_PlaceRail(TileIndex tile, int cmd, uint32 railtype)
+{
+ CP_DoCommand(tile, railtype, cmd, NULL,
+ CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK)
+ );
+}
+
+void CopyPaste::CP_PlaceSignals(TileIndex tile, Track track, SignalType type, uint direction, bool semaphore)
+{
+ if (IsPbsSignal(type) && direction > 0) direction--;
+ CP_DoCommand(tile, track | (semaphore ? 1 : 0) << 4 | type << 5 | direction << 15, 0, NULL,
+ CMD_BUILD_SIGNALS | CMD_MSG(STR_ERROR_CAN_T_BUILD_SIGNALS_HERE));
+}
+
+void CopyPaste::CP_PlaceRoad(TileIndex tile, uint8 road_bits)
+{
+ CP_DoCommand(tile, road_bits, 0, NULL, CMD_BUILD_ROAD | CMD_MSG(STR_ERROR_CAN_T_BUILD_ROAD_HERE));
+}
+
+void CopyPaste::CP_PlaceRoadStop(TileIndex tile, uint8 direction, uint8 roadtype, bool truck_stop, bool drive_through)
+{
+ CP_DoCommand(tile, direction, truck_stop | drive_through << 1 | roadtype << 2 | INVALID_STATION << 16, NULL, CMD_BUILD_ROAD_STOP | CMD_MSG(truck_stop ? STR_ERROR_CAN_T_BUILD_TRUCK_STATION : STR_ERROR_CAN_T_BUILD_BUS_STATION));
+}
+
+void CopyPaste::CP_PlaceRail_Tunnel(TileIndex tile, uint32 railtype)
+{
+ CP_DoCommand(tile, railtype, 0, NULL,
+ CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE));
+}
+
+void CopyPaste::CP_PlaceRoad_Tunnel(TileIndex tile, uint8 roadtype)
+{
+ CP_DoCommand(tile, 0x200 | roadtype, 0, NULL, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE));
+}
+
+void CopyPaste::CP_Build_Bridge(TileIndex start, TileIndex end, uint8 bridgetype, uint8 transport_type, uint8 rail_road_type)
+{
+ CP_DoCommand(end, start,
+ bridgetype | (rail_road_type << 8) | (transport_type << 15), NULL,
+ CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE));
+}
+
+void CopyPaste::CP_PlaceRail_Depot(TileIndex tile, uint8 railtype, uint8 direction)
+{
+ CP_DoCommand(tile, railtype, direction, NULL,
+ CMD_BUILD_TRAIN_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT));
+}
+
+void CopyPaste::CP_PlaceRoad_Depot(TileIndex tile, uint8 direction_type)
+{
+ CP_DoCommand(tile, direction_type, 0, NULL,
+ CMD_BUILD_ROAD_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_ROAD_HERE));
+}
+
+void CopyPaste::CP_PlaceWaypoint(TileIndex tile, uint8 waypoint_type)
+{
+ CP_DoCommand(tile, waypoint_type, 0, NULL, CMD_BUILD_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT));
+}
+
+void CopyPaste::CP_ClearTile(TileIndex start_tile, TileIndex end_tile)
+{
+ CP_DoCommand(start_tile, end_tile, 0, NULL, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA));
+}
+
+uint8 CopyPaste::MirrorSignalDirection(uint8 direction)
+{
+ if (direction == 0) return direction;
+ return (direction == 1 ? 2 : 1);
+}
+
+DisallowedRoadDirections CopyPaste::MirrorOneWayRoadDirection(DisallowedRoadDirections drd)
+{
+ if (drd == DRD_NONE || drd == DRD_BOTH) return drd;
+ return drd == DRD_SOUTHBOUND ? DRD_NORTHBOUND : DRD_SOUTHBOUND;
+}
+
+void CopyPaste::SwapSignalInfo(uint index)
+{
+ uint16 signal = m_signals[index];
+ /* Clear bit 2-16 */
+ for (uint i = 2; i < 16; i++)
+ ClrBit(m_signals[index], i);
+ /* Set bit 2 to former 3 */
+ SB(m_signals[index], 2, 1, GB(signal, 3, 1));
+ /* Set bit 3 to former 2 */
+ SB(m_signals[index], 3, 1, GB(signal, 2, 1));
+ /* Set bit 6+7 to former 8+9 */
+ SB(m_signals[index], 6, 2, MirrorSignalDirection(GB(signal, 8, 2)));
+ /* Set bit 8+9 to former 6+7 */
+ SB(m_signals[index], 8, 2, MirrorSignalDirection(GB(signal, 6, 2)));
+ /* Exchange signal types too */
+ /* Set bit 10-12 to former 13-15 */
+ SB(m_signals[index], 10, 3, GB(signal, 13, 3));
+ /* Set bit 13-15 to former 10-12 */
+ SB(m_signals[index], 13, 3, GB(signal, 10, 3));
+}
+
+/** This function pastes landscape */
+void CopyPaste::PasteLandscape(TileIndex tile)
+{
+ TileIndex sx = TileX(tile);
+ TileIndex sy = TileY(tile);
+ uint size_x = GetWidth();
+ uint size_y = GetHeight();
+ int8 count, h_diff;
+ uint h_tile;
+
+ TileIndex index;
+ /* Base height level is from upper right tile. */
+ uint baseh = TileHeight(tile);
+ /* Bulldoze tiles which will be built on */
+ if (m_clear_before_build) {
+ index = 0;
+ TILE_LOOP(tile, size_x - 1, size_y - 1, TileXY(sx, sy)) {
+
+ if (GetCPTileType(index) != CP_TILE_CLEAR) {
+ CP_ClearTile(tile, tile);
+ }
+ index++;
+
+ }
+ }
+
+ /* Check if we want to restore any terrain at all */
+ if (m_paste_vacant_terrain > 0) {
+ /* Restore terrain
+ * Please look into "CopyArea" for details on which bit is used for which information
+ */
+ index = 0;
+ TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
+
+ if (HasBit(m_terrain_needed[index], 0) || (m_paste_vacant_terrain == 2)) {
+
+ /* Do special heightlevel calculations if we are networking,
+ * since we cannot measure the heightlevel if we delay the execution.
+ * Lowering/Raising land affects neighbour tiles too...
+ * Else we just use the current tileheight we get from the map.
+ */
+#ifdef ENABLE_NETWORK
+ if (_networking) {
+ h_tile = TileHeight(tile);
+ if ((cur_h != size_y) && (cur_w != size_x)) {
+ /* Look NE and NW */
+ h_tile = ClampToRight(index, baseh, h_tile);
+ h_tile = ClampToUp(index, baseh, h_tile, size_x);
+ /* use clamped height instead of actual height */
+ h_diff = GetHeight(baseh, index) - h_tile;
+ }
+ else {
+ if ((cur_h == size_y) && (cur_w == size_x)) {
+ /* First Tile is always at baseh */
+ h_diff = GetHeight(baseh, index) - TileHeight(tile);
+ }
+ else if (cur_w == size_x) {
+ /* Right Border, clamp to upper tile only */
+ h_tile = ClampToUp(index, baseh, h_tile, size_x);
+ h_diff = GetHeight(baseh, index) - h_tile;
+ }
+ else {
+ /* Upper Border, clamp to right tile only */
+ h_tile = ClampToRight(index, baseh, h_tile);
+ h_diff = GetHeight(baseh, index) - h_tile;
+ }
+ }
+ }
+ else
+#endif /* ENABLE_NETWORK */
+ h_diff = GetHeight(baseh, index) - TileHeight(tile);
+
+ /* Now raise/lower the tile according to our calculations */
+ if (h_diff > 0) {
+ for (count = 0; count < h_diff; count++)
+ CP_RaiseLowerLand(tile, 1);
+ }
+ else if (h_diff < 0) {
+ for (count = h_diff; count < 0; count++)
+ CP_RaiseLowerLand(tile, 0);
+ }
+ }
+ index++;
+
+ }
+ }
+
+}
+
+/** This function pastes signals for a given index */
+void CopyPaste::PasteSignals(uint index, TileIndex tile)
+{
+ uint16 signal = m_signals[index];
+ if (m_toggle_signal_direction) {
+ SB(signal, 6, 2, MirrorSignalDirection(GB(signal, 6, 2)));
+ SB(signal, 8, 2, MirrorSignalDirection(GB(signal, 8, 2)));
+ }
+ bool firstrun = true;
+ for (Track t = TRACK_BEGIN; t < TRACK_END; t++) {
+ if (m_railroad[index] & TrackToTrackBits(t)) {
+ if (((IsDiagonalTrack(t) || t == TRACK_LEFT || t == TRACK_UPPER) &&
+ HasBit(signal, 0)) ||
+ ((t == TRACK_RIGHT || t == TRACK_LOWER) && HasBit(signal, 1))) {
+ CP_PlaceSignals(tile, t,
+ (SignalType)GB(signal, firstrun ? 10 : 13, 3),
+ GB(signal, firstrun ? 6 : 8, 2),
+ HasBit(signal, firstrun ? 2 : 3));
+ firstrun = false;
+ }
+ }
+ }
+}
+
+/** This function calculates the height,
+ * the given tile will have, after the neighbour(right) tile is restored.
+ * In OTTD adjacent tiles may only differ in height by 1 level.
+ */
+int8 CopyPaste::ClampToRight(TileIndex index, int8 baseh, int8 h_tile)
+{
+ int8 h_right = GetHeight(baseh, index - 1);
+
+ if (h_tile > (h_right + 1)) {
+ h_tile = h_right + 1;
+ }
+ else if (h_tile < (h_right - 1)) {
+ h_tile = h_right - 1;
+ }
+
+ return h_tile;
+}
+
+/** This function calculates the height,
+ * the given tile will have, after the neighbour(upper) tile is restored.
+ * In OTTD adjacent tiles may only differ in height by 1 level.
+ */
+int8 CopyPaste::ClampToUp(TileIndex index, int8 baseh, int8 h_tile, int32 size_x)
+{
+ int8 h_up = GetHeight(baseh, index - size_x);
+
+ if (h_tile > (h_up + 1)) {
+ h_tile = h_up + 1;
+ }
+ else if (h_tile < (h_up - 1)) {
+ h_tile = h_up - 1;
+ }
+
+ return h_tile;
+}
+
+/** Game command which pastes the copied content.
+ * The result depends on setting some variables:
+ * m_paste_vacant_terrain, m_convert_rail, m_clear_before_build and m_toggle_signal_direction
+ * @param tile upper right corner to paste to
+ */
+void CopyPaste::internal_PasteArea(TileIndex tile)
+{
+ TileIndex index = 0;
+ int32 size_x, size_y;
+ bool success = true;
+ TileIndex sx = TileX(tile);
+ TileIndex sy = TileY(tile);
+ TileIndex ex = sx + GetWidth();
+ TileIndex ey = sy + GetHeight();
+
+ /* Reset paste costs */
+ if (_shift_pressed) {
+ m_costs.MultiplyCost(0);
+ }
+
+ /* Nothing copied? exit... */
+ if (! IsSomethingCopied()) return;
+
+ /* Paste out of map? exit... */
+ if ((ex >= MapSizeX()) || (ey >= MapSizeY())) return;
+
+ size_x = GetWidth();
+ size_y = GetHeight();
+
+ /* Restore the landscape */
+ PasteLandscape(tile);
+
+ /* Paste Rail, Depot, Tunnel, Road, Bridge:
+ * Please look into "CopyArea" for details on which bit is used for which information
+ */
+ index = 0;
+ TILE_LOOP(tile, size_x - 1, size_y - 1, TileXY(sx, sy)) {
+
+ uint minortt = GetCPMinorTileType(index);
+
+ switch(GetCPTileType(index)) {
+ case CP_TILE_RAIL: {
+ uint rt = GB(m_railroad[index], 6, 2); //railtype
+ switch (minortt) {
+ case RAIL_TILE_NORMAL:
+ case RAIL_TILE_SIGNALS:
+// case RAIL_TILE_WAYPOINT:
+ for (Track t = TRACK_BEGIN; t < TRACK_END; t++) {
+ if (m_railroad[index] & TrackToTrackBits(t)) CP_PlaceRail(tile, t, m_convert_rail ? (uint)_cur_railtype : rt);
+ }
+ break;
+
+ case RAIL_TILE_DEPOT:
+ CP_PlaceRail_Depot(tile, m_convert_rail ? (uint)_cur_railtype : rt, GB(m_railroad[index], 0, 2));
+ break;
+ }
+ } break;
+ case CP_TILE_ROAD: {
+ switch(minortt) {
+ case ROAD_TILE_CROSSING:
+ CP_PlaceRail(tile, GB(m_railroad[index], 0, 4) == ROAD_X ? TRACK_Y : TRACK_X, m_convert_rail ? (uint)_cur_railtype : GB(m_signals[index], 4, 2));
+ /* fallthrough */
+ case ROAD_TILE_NORMAL:
+ if (GB(m_railroad[index], 0, 4) > 0) CP_PlaceRoad(tile, GB(m_railroad[index], 0, 4) | (ROADTYPE_ROAD << 4) | (minortt == ROAD_TILE_NORMAL ? (GB(m_signals[index], 0, 2) << 6) : 0));
+ if (GB(m_railroad[index], 4, 4) > 0) CP_PlaceRoad(tile, GB(m_railroad[index], 4, 4) | (ROADTYPE_TRAM << 4));
+ break;
+ case ROAD_TILE_DEPOT:
+ CP_PlaceRoad_Depot(tile, GB(m_railroad[index], 0, 2) | HasBit(m_railroad[index], 2) << 2);
+ break;
+ }
+ } break;
+ case CP_TILE_STATION:
+ switch(minortt) {
+ case CP_TILE_ROAD:
+ CP_PlaceRoadStop(tile, GB(m_railroad[index], 0, 2), GB(m_railroad[index], 6, 2), HasBit(m_railroad[index], 2), HasBit(m_railroad[index], 3));
+ }
+
+
+ case CP_TILE_TUNNELBRIDGE:
+ if (HasBit(minortt, 0)) {
+ /* Tunnels:
+ * TODO: check if tunnel end will be at right place (=inside area)
+ * Same check as bridge? move into tunneldir, until tunneltile reached
+ */
+ if (HasBit(m_railroad[index], 4)) {
+ if (GB(m_railroad[index], 2, 2) == TRANSPORT_ROAD) {
+ CP_PlaceRoad_Tunnel(tile, GB(m_railroad[index], 6, 2));
+ } else {
+ CP_PlaceRail_Tunnel(tile, m_convert_rail ? (uint) _cur_railtype : GB(m_railroad[index], 6, 2));
+ }
+ }
+ } else if (HasBit(m_railroad[index], 4)) {
+ /* Bridges: */
+ /* If we get here, there is a bridge start here. Now find the bridge end
+ * TODO Shorten code by setting up variables inside switch statement, and use them inside one loop at the end
+ */
+ bool bridge_error = false;
+ TileIndex tmp_tile = tile;
+ uint rdd = ReverseDiagDir((DiagDirection)GB(m_railroad[index], 0, 2));
+ bool found = false;
+ TileIndex i;
+ switch (GB(m_railroad[index], 0, 2)) {
+ case DIAGDIR_NE:
+ /* -X */
+ i = 1;
+ while ((TileX(tile) - i) >= sx) {
+ if (GetCPTileType(index - i) == CP_TILE_TUNNELBRIDGE &&
+ !HasBit(GetCPMinorTileType(index - i), 0) &&
+ !HasBit(m_railroad[index - i], 4) &&
+ GB(m_railroad[index - i], 0, 2) == rdd) {
+ found = true;
+ break;
+ }
+ i++;
+ }
+ if ((TileX(tile) - i) < sx || !found)
+ bridge_error = true;
+ else
+ tmp_tile += TileDiffXY(0 - i, 0);
+ break;
+ case DIAGDIR_SW:
+ /* +X */
+ i = 1;
+ while ((TileX(tile) + i) < (sx + size_x - 1)) {
+ if (GetCPTileType(index + i) == CP_TILE_TUNNELBRIDGE && !HasBit(GetCPMinorTileType(index + i), 0) && !HasBit(m_railroad[index + i], 4) && GB(m_railroad[index + i], 0, 2) == rdd) {
+ found = true;
+ break;
+ }
+ i++;
+ }
+ if ((TileX(tile) + i) >= (sx + size_x - 1) || !found)
+ bridge_error = true;
+ else
+ tmp_tile += TileDiffXY(+i, 0);
+ break;
+ case DIAGDIR_SE:
+ /* +Y */
+ i = 1;
+ while ((TileY(tile) + i) < (sy + size_y - 1)) {
+ if (GetCPTileType(index + (i * (size_x - 1))) == CP_TILE_TUNNELBRIDGE && !HasBit(GetCPMinorTileType(index + (i * (size_x - 1))), 0) && !HasBit(m_railroad[index + (i * (size_x - 1))], 4) && GB(m_railroad[index + (i * (size_x - 1))], 0, 2) == rdd) {
+ found = true;
+ break;
+ }
+ i++;
+ }
+ if ((TileY(tile) + i) >= (sy + size_y - 1) || !found)
+ bridge_error = true;
+ else
+ tmp_tile += TileDiffXY(0, +i);
+ break;
+ case DIAGDIR_NW:
+ /* -Y */
+ i = 1;
+ while ((TileY(tile) + i) >= (sy + size_y - 1)) {
+ if (GetCPTileType(index - (i * (size_x - 1))) == CP_TILE_TUNNELBRIDGE && !HasBit(GetCPMinorTileType(index - (i * (size_x - 1))), 0) && !HasBit(m_railroad[index - (i * (size_x - 1))], 4) && GB(m_railroad[index - (i * (size_x - 1))], 0, 2) == rdd) {
+ found = true;
+ break;
+ }
+ i++;
+ }
+ if ((TileY(tile) - i) < sy || !found)
+ bridge_error = true;
+ else
+ tmp_tile += TileDiffXY(0, 0 - i);
+ break;
+ }
+ if (!bridge_error) {
+ if (GB(m_railroad[index], 2, 2) == TRANSPORT_RAIL) {
+ CP_Build_Bridge(tile, tmp_tile, m_convert_rail ? GetFastestAvailableBridgeType(GetTunnelBridgeLength(tile, tmp_tile)) : m_signals[index], TRANSPORT_RAIL, m_convert_rail ? (uint) _cur_railtype : ((m_railroad[index] >> 6) & 3U) );
+ } else {
+ CP_Build_Bridge(tile, tmp_tile, m_convert_rail ? GetFastestAvailableBridgeType(GetTunnelBridgeLength(tile, tmp_tile)) : m_signals[index], TRANSPORT_ROAD, ((m_railroad[index] >> 6) & 3U) );
+ }
+ }
+ }
+ break;
+ default: break;
+ }
+
+ index++;
+
+ }
+
+ /* Restore Signals and Waypoints (separated because they depend on underlying track) */
+ index = 0;
+ TILE_LOOP(tile, size_x - 1, size_y - 1, TileXY(sx, sy)) {
+ if (GetCPTileType(index) == CP_TILE_RAIL) {
+ switch(GetCPMinorTileType(index)) {
+/* case RAIL_TILE_WAYPOINT:
+ CP_PlaceWaypoint(tile, GB(m_signals[index], 0, 8));
+ break;*/
+ case RAIL_TILE_SIGNALS:
+ PasteSignals(index, tile);
+ }
+ }
+ index++;
+ }
+
+
+ /* If shift is pressed, show the cost estimate. Else play a sound on success */
+ if (_shift_pressed) {
+ ShowEstimatedCostOrIncome(m_costs.GetCost(), 100, 100);
+ }
+ else {
+ if (success) SndPlayTileFx(SND_1F_SPLAT, index);
+ }
+}
+
+/**
+ * Safe Paste Command.
+ * Checks CopyPasteCommandQueue-Size in network games
+ **/
+void CopyPaste::PasteArea(TileIndex tile)
+{
+ if (_settings_client.gui.cp_paste_speed != 0xFF) {
+ this->internal_PasteArea(tile);
+ }
+ else {
+ ShowErrorMessage(STR_COPY_PASTE_PASTE_DISABLED, INVALID_STRING_ID, WL_ERROR, TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE);
+ }
+}
+
+/**
+ * Indicates this tile needs to be terraformed, in order to restore some building.
+ * Bit 0 indicates this tile is needed for terraforming,
+ * but is not directly build on.
+ * Bit 1 indicates this tile is beeing built on.
+ **/
+void CopyPaste::TerrainNeededAroundTile(TileIndex tindex, TileIndex bindex)
+{
+ /* always restore terrain on this tiles */
+ SetBit(m_terrain_needed[tindex], 0);
+ SetBit(m_terrain_needed[tindex + 1], 0);
+ SetBit(m_terrain_needed[tindex + GetWidth()], 0);
+ SetBit(m_terrain_needed[tindex + GetWidth() + 1], 0);
+}
+
+/**
+ * Game command which copies a selected area
+ **/
+void CopyPaste::CopyArea(TileIndex end, TileIndex start)
+{
+ int8 baseh;
+ TileIndex tindex = 0;
+ TileIndex bindex = 0;
+ int size_x, size_y;
+ bool success = false;
+ TileIndex sx = TileX(start);
+ TileIndex sy = TileY(start);
+ TileIndex ex = TileX(end);
+ TileIndex ey = TileY(end);
+ bool tunnelbridge_error;
+ int32 maxdiff, i;
+
+
+ if (ex < sx) Swap(ex, sx);
+ if (ey < sy) Swap(ey, sy);
+ /* add one tile, but just for heightmap */
+ ex++;
+ ey++;
+ size_x = (ex - sx) + 1;
+ size_y = (ey - sy) + 1;
+
+ this->AllocateMapArray(size_x * size_y);
+ SetWidth(size_x);
+ SetHeight(size_y);
+
+ /* Create a command DIFF to a flat Area */
+ /* Base level is from first tile. */
+ baseh = (int8)TileHeight(TileXY(sx, sy));
+ tindex = 0;
+ TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
+
+ m_heightmap[tindex] = ((int8)TileHeight(tile)) - baseh;
+ tindex++;
+
+ /* Dont Copy tracks/buildings on last x/y row */
+ if (cur_h == 1 || cur_w == 1) {
+ success = true;
+ continue;
+ }
+
+ /* Copy building/track here */
+ switch (GetTileType(tile)) {
+ case MP_RAILWAY:
+ /* Check if we want to copy this type of building */
+ if (!m_copy_with_rail) break;
+ if (!(m_copy_with_other || IsTileOwner(tile, _current_company))) break;
+ SB(m_tiletype[bindex], 0, 4, CP_TILE_RAIL);
+ SB(m_tiletype[bindex], 4, 4, GetRailTileType(tile));
+ TerrainNeededAroundTile(tindex - 1, bindex);
+
+ /* Store Railway type in bits 6+7 */
+ SB(m_railroad[bindex], 6, 2, GetRailType(tile));
+
+ switch (GetRailTileType(tile)) {
+ case RAIL_TILE_DEPOT:
+ /* Depot here */
+ /* store direction: bit 2+3 */
+ SB(m_railroad[bindex], 0, 2, GetDepotDirection(tile, TRANSPORT_RAIL));
+ break;
+/* case RAIL_TILE_WAYPOINT:
+ // Waypoint here
+ // Store Waypoint custom gfx id
+ SB(m_signals[bindex], 0, 8, GetWaypointByTile(tile)->stat_id);
+ // Store axis
+ SB(m_railroad[bindex], 0, 2, AxisToTrackBits(GetWaypointAxis(tile)));
+ break;*/
+ case RAIL_TILE_SIGNALS: {
+ /* Signals: */
+ /* Store Signal:
+ * Bit 0 : signal 1 present
+ * Bit 1 : signal 2 present
+ * Bit 2 : variant S1
+ * Bit 3 : variant S2
+ * Bits: 6- 7 : Direction S1 (Clicks to build)
+ * Bits: 8- 9 : Direction S2 (Clicks to build)
+ * Bits: 10-12: signal type S1
+ * Bits: 13-15: signal type S2
+ */
+ bool first_run = true;
+ for (Track t = TRACK_BEGIN; t < TRACK_END; t++) {
+ if (HasTrack(tile, t) && HasSignalOnTrack(tile, t)) {
+ if (t == TRACK_X || t == TRACK_Y || t == TRACK_LEFT || t == TRACK_UPPER) {
+ SetBit(m_signals[bindex], 0);
+ } else {
+ SetBit(m_signals[bindex], 1);
+ }
+ /* Store signal direction */
+ Trackdir td = TrackToTrackdir(t);
+ if (!(HasSignalOnTrackdir(tile, td) && HasSignalOnTrackdir(tile, ReverseTrackdir(td)))) {
+ /* one way signal, not 2-way */
+ if (t == TRACK_LEFT || t == TRACK_RIGHT) td = ReverseTrackdir(td);
+ SB(m_signals[bindex], first_run ? 6 : 8, 2, HasSignalOnTrackdir(tile, td) ? 1 : 2);
+ }
+ /* Bit 2/3: signal variant(semaphore/electric) ToDo: find some place this can live with another one */
+ SB(m_signals[bindex], first_run ? 2 : 3, 1, GetSignalVariant(tile, t));
+ /* Bits 10 - 12/13-15: signal type */
+ SB(m_signals[bindex], first_run ? 10 : 13, 3, GetSignalType(tile, t));
+ first_run = false;
+ }
+ }
+ }
+ /* fallthrough */
+ case RAIL_TILE_NORMAL:
+ /* Store Railway tracks in bits 0 to 5: */
+ m_railroad[bindex] |= GetTrackBits(tile);
+ break;
+ }
+
+ break;
+ case MP_ROAD:
+ if (GetRoadTileType(tile) != ROAD_TILE_CROSSING && (!m_copy_with_road || !(m_copy_with_other || IsTileOwner(tile, _current_company)))) break;
+ SB(m_tiletype[bindex], 0, 4, CP_TILE_ROAD);
+ SB(m_tiletype[bindex], 4, 4, GetRoadTileType(tile));
+ switch (GetRoadTileType(tile)) {
+ case ROAD_TILE_CROSSING: {
+ /* Crossing: Get Axis, store railtype too
+ * TODO Unify...
+ */
+ RoadBits roadbits = GetCrossingRoadBits(tile);
+ Track railtrack = GetCrossingRailTrack(tile);
+ bool should_copy_rail = m_copy_with_rail && (m_copy_with_other || IsTileOwner(tile, _current_company));
+ bool should_copy_road = m_copy_with_road;
+ if (should_copy_rail && !should_copy_road) {
+ SB(m_tiletype[bindex], 0, 4, CP_TILE_RAIL);
+ SB(m_tiletype[bindex], 4, 4, RAIL_TILE_NORMAL);
+ TerrainNeededAroundTile(tindex - 1, bindex);
+ /* Copy the rail */
+ m_railroad[bindex] |= TrackToTrackBits(railtrack);
+ SB(m_railroad[bindex], 6, 2, GetRailType(tile));
+ }
+ if (should_copy_road && !should_copy_rail) {
+ SB(m_tiletype[bindex], 4, 4, ROAD_TILE_NORMAL);
+ }
+ if (should_copy_road && should_copy_rail) {
+ SB(m_signals[bindex], 4, 2, GetRailType(tile));
+ }
+ if (should_copy_road) {
+ /* Copy the road */
+ for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) {
+ if ((m_copy_with_other || GetRoadOwner(tile, rt) == _current_company) && GetRoadTypes(tile) & RoadTypeToRoadTypes(rt)) {
+ TerrainNeededAroundTile(tindex - 1, bindex);
+ SB(m_railroad[bindex], rt * 4, 4, roadbits);
+ }
+ }
+ }
+ if (!should_copy_road && !should_copy_rail) {
+ SB(m_tiletype[bindex], 0, 4, CP_TILE_CLEAR);
+ }
+ } break;
+
+ case ROAD_TILE_DEPOT:
+ /* Direction: bit 0+1 */
+ SB(m_railroad[bindex], 0, 2, GetDepotDirection(tile, TRANSPORT_ROAD));
+ /* Tram or Road? bit 2 */
+ if (GetRoadTypes(tile) != ROADTYPES_ROAD) SetBit(m_railroad[bindex], 2);
+ TerrainNeededAroundTile(tindex - 1, bindex);
+ break;
+
+ case ROAD_TILE_NORMAL:
+ for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) {
+ SB(m_railroad[bindex], rt * 4, 4, GetRoadBits(tile, rt));
+ }
+ TerrainNeededAroundTile(tindex - 1, bindex);
+ SB(m_signals[bindex], 0, 2, GetDisallowedRoadDirections(tile));
+ break;
+ }
+ break;
+
+ case MP_STATION:
+ /* Stations: currently partially supported */
+ SB(m_tiletype[bindex], 0, 4, CP_TILE_STATION);
+
+
+ switch (GetStationType(tile)) {
+ /* Road stations */
+ case STATION_TRUCK:
+ case STATION_BUS:
+ SB(m_tiletype[bindex], 4, 4, CP_TILE_ROAD);
+
+ SB(m_railroad[bindex], 0, 2, GetRoadStopDir(tile));
+ if(GetStationType(tile) == STATION_TRUCK) SetBit(m_railroad[bindex], 2);
+ SB(m_railroad[bindex], 3, 1, IsDriveThroughStopTile(tile));
+ SB(m_railroad[bindex], 6, 2, GetRoadTypes(tile));
+ break;
+
+ /* Rail stations */
+ case STATION_RAIL:
+ SB(m_tiletype[bindex], 4, 4, CP_TILE_RAIL);
+
+ //GetStationSpec for newgrf info
+ break;
+
+ default:
+ /* Not reached */
+ break;
+
+ }
+ break;
+
+ case MP_TUNNELBRIDGE:
+ /* Check for tunnel or bridge
+ * TODO Try to unify bridges an tunnels, since error checking(start/endtile) is essentially the same
+ */
+ if (IsTunnelTile(tile)) {
+ /* Storing Tunnel */
+ if (!m_copy_with_rail && (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL)) break;
+ if (!m_copy_with_road && (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD)) break;
+ if (!(m_copy_with_other || IsTileOwner(tile, _current_company))) break;
+ tunnelbridge_error = false;
+ if ((GetTunnelBridgeDirection(tile) == DIAGDIR_SW) || (GetTunnelBridgeDirection(tile) == DIAGDIR_SE)) {
+ int tilediff = 1;
+ /* Store tunnel direction in bit 0-1 */
+ SB(m_railroad[bindex], 0, 2, GetTunnelBridgeDirection(tile));
+ /* Store tunnel transport type in bit 2-3 */
+ SB(m_railroad[bindex], 2, 2, GetTunnelBridgeTransportType(tile));
+ /* Store tunnel start in bit 4 */
+ SetBit(m_railroad[bindex], 4);
+ /* Store rail type too, if it is a railtunnel */
+ if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL)
+ m_railroad[bindex] |= (GetRailType(tile) << 6);
+ if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD)
+ m_railroad[bindex] |= (GetRoadTypes(tile) << 6);
+ /* Now mark all tiles between tunnel start and end as needed
+ * TODO Unify... ;)
+ */
+ switch (GetTunnelBridgeDirection(tile)) {
+ case DIAGDIR_SW:
+ maxdiff = (size_x - 1) - (bindex % (size_x - 1)) - 1;
+ if (maxdiff <= 0) {
+ tunnelbridge_error = true;
+ break;
+ }
+ while ((!IsTunnelTile(tile + TileDiffXY(tilediff, 0))) && (tilediff <= maxdiff)) { //InsideSelection, tunnelEndnotfound
+ tilediff++;
+ }
+ if ((!IsTunnelTile(tile + TileDiffXY(tilediff, 0))) || (tilediff > maxdiff))
+ tunnelbridge_error = true;
+ if (!tunnelbridge_error) {
+ /* Mark Tiles as needed: */
+ for (i = 0; i <= tilediff; i++)
+ TerrainNeededAroundTile(tindex - 1 + i, bindex + i);
+
+ /* Set other TunnelEnd */
+ SB(m_tiletype[bindex + tilediff], 0, 4, CP_TILE_TUNNELBRIDGE);
+ SB(m_tiletype[bindex + tilediff], 4, 1, true);
+ /* Store tunnel direction in bit 1-2 */
+ m_railroad[bindex + tilediff] |= GetTunnelBridgeDirection(tile + TileDiffXY(tilediff, 0));
+ /* Store tunnel transport type in bit 3 */
+ SB(m_railroad[bindex + tilediff], 2, 2, GetTunnelBridgeTransportType(tile + TileDiffXY(tilediff, 0)));
+ /* Store tunnel start in bit 4 (No, this is tunnel End) */
+ /* Store rail type too, if railtunnel */
+ if (GetTunnelBridgeTransportType(tile + TileDiffXY(tilediff, 0)) == TRANSPORT_RAIL)
+ m_railroad[bindex + tilediff] = (GetRailType(tile + TileDiffXY(tilediff, 0)) << 6);
+ }
+ break;
+ case DIAGDIR_SE:
+ maxdiff = (size_y - 1) - (bindex / (size_x - 1)) - 1;
+ if (maxdiff <= 0) {
+ tunnelbridge_error = true;
+ break;
+ }
+ while ((!IsTunnelTile(tile + TileDiffXY(0, tilediff))) && (tilediff <= maxdiff)) { //InsideSelection, tunnelEndnotfound
+ tilediff++;
+ }
+ if ((!IsTunnelTile(tile + TileDiffXY(0, tilediff))) || (tilediff > maxdiff))
+ tunnelbridge_error = true;
+ if (!tunnelbridge_error) {
+ /* Mark Tiles as needed: */
+ for (i = 0; i <= tilediff; i++)
+ TerrainNeededAroundTile(tindex - 1 + (i * size_x), bindex + (i * (size_x - 1)));
+
+ /* Set other TunnelEnd */
+ SB(m_tiletype[bindex + tilediff * (size_x - 1)], 0, 4, CP_TILE_TUNNELBRIDGE);
+ SB(m_tiletype[bindex + tilediff * (size_x - 1)], 4, 1, true);
+ /* Store tunnel direction in bit 0-1 */
+ m_railroad[bindex + (tilediff * (size_x - 1))] |= GetTunnelBridgeDirection(tile + TileDiffXY(0, tilediff));
+ /* Store tunnel transport type in bit 3 */
+ SB(m_railroad[bindex + tilediff * (size_x - 1)], 2, 2, GetTunnelBridgeTransportType(tile + TileDiffXY(0, tilediff)));
+ /* Store tunnel start in bit 4 (No, this is tunnel End) */
+ /* Store rail type too, if railtunnel */
+ if (GetTunnelBridgeTransportType(tile + TileDiffXY(0, tilediff)) == TRANSPORT_RAIL)
+ m_railroad[bindex + (tilediff * (size_x - 1))] |= (GetRailType(tile + TileDiffXY(0, tilediff)) << 6);
+ }
+ break;
+ default:
+ break;
+ }
+ if (tunnelbridge_error) {
+ /* ResetBridge on Error */
+ m_railroad[bindex] = 0;
+ } else {
+ SB(m_tiletype[bindex], 0, 4, CP_TILE_TUNNELBRIDGE);
+ SB(m_tiletype[bindex], 4, 1, IsTunnelTile(tile));
+ }
+ }
+ else {
+ /* Other directions: do nothing since we have everything copied already */
+ }
+ }
+ else {
+ /* Store bridge (Has to be in "else", since Tunnel is a "BridgeRamp" too) */
+ if (IsBridge(tile)) {
+ if (!m_copy_with_rail && (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL)) break;
+ if (!m_copy_with_road && (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD)) break;
+ if (!(m_copy_with_other || IsTileOwner(tile, _current_company))) break;
+
+ tunnelbridge_error = false;
+ if ((GetTunnelBridgeDirection(tile) == DIAGDIR_SW) || (GetTunnelBridgeDirection(tile) == DIAGDIR_SE)) {
+ int tilediff = 1;
+ /* Direction bit 0-1 */
+ SB(m_railroad[bindex], 0, 2, GetTunnelBridgeDirection(tile));
+ /* TransportType bit 3 */
+ SB(m_railroad[bindex], 2, 2, GetTunnelBridgeTransportType(tile));
+ /* Store "IsBridge-Start" in Bit4 */
+ SetBit(m_railroad[bindex], 4);
+ /* BridgeType in m_signals */
+ m_signals[bindex] = GetBridgeType(tile);
+ /* Store Railtype */
+ if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL)
+ m_railroad[bindex] |= (GetRailType(tile) << 6);
+ if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD)
+ m_railroad[bindex] |= (GetRoadTypes(tile) << 6);
+ /* Now mark all tiles between bridge start and end as needed
+ * TODO: Unify :)
+ */
+ switch (GetTunnelBridgeDirection(tile)) {
+ TileIndex otherEnd;
+ case DIAGDIR_SW:
+ maxdiff = (size_x - 1) - (bindex % (size_x - 1)) - 1;
+ if (maxdiff <= 0) {
+ tunnelbridge_error = true;
+ break;
+ }
+ otherEnd = GetOtherBridgeEnd(tile);
+ tilediff = DistanceManhattan(tile, otherEnd);
+ if (tilediff > maxdiff)
+ tunnelbridge_error = true;
+
+ if (!tunnelbridge_error) {
+ /* Mark Tiles as needed: */
+ for (i = 0; i <= tilediff; i++)
+ TerrainNeededAroundTile(tindex - 1 + i, bindex + i);
+
+ /* Set other BridgeEnd */
+ SB(m_tiletype[bindex + tilediff], 0, 4, CP_TILE_TUNNELBRIDGE);
+ SB(m_tiletype[bindex + tilediff], 4, 1, IsTunnelTile(tile));
+ /* Direction bit 0-1 */
+ SB(m_railroad[bindex + tilediff], 0, 2, GetTunnelBridgeDirection(tile + TileDiffXY(tilediff, 0)));
+ /* TransportType bit 3 */
+ SB(m_railroad[bindex + tilediff], 2, 2, GetTunnelBridgeTransportType(tile + TileDiffXY(tilediff, 0)));
+ /* Store "IsBridge-Start" in Bit4 (Nope, this is the Bridge-End) */
+
+ /* BridgeType in m_signals */
+ m_signals[bindex + tilediff] = GetBridgeType(tile + TileDiffXY(tilediff, 0));
+ /* Store Railtype */
+ if (GetTunnelBridgeTransportType(tile + TileDiffXY(tilediff, 0)) == TRANSPORT_RAIL)
+ m_railroad[bindex + tilediff] |= (GetRailType(tile + TileDiffXY(tilediff, 0)) << 6);
+ }
+ break;
+ case DIAGDIR_SE:
+ maxdiff = (size_y - 1) - (bindex / (size_x - 1)) - 1;
+ if (maxdiff <= 0) {
+ tunnelbridge_error = true;
+ break;
+ }
+ otherEnd = GetOtherBridgeEnd(tile);
+ tilediff = DistanceManhattan(tile, otherEnd);
+ if (tilediff > maxdiff)
+ tunnelbridge_error = true;
+ if (!tunnelbridge_error) {
+ /* Mark Tiles as needed: */
+ for (i = 0; i <= tilediff; i++)
+ TerrainNeededAroundTile(tindex - 1 + (i * size_x), bindex + (i * (size_x - 1)));
+
+ /* Set other BridgeEnd */
+ SB(m_tiletype[bindex + (tilediff * (size_x - 1))], 0, 4, CP_TILE_TUNNELBRIDGE);
+ SB(m_tiletype[bindex + (tilediff * (size_x - 1))], 4, 1, IsTunnelTile(tile));
+ /* Direction bit 0-1 */
+ SB(m_railroad[bindex + tilediff * (size_x - 1)], 0, 2, GetTunnelBridgeDirection(tile + TileDiffXY(0, tilediff)));
+ /* TransportType bit 3 */
+ SB(m_railroad[bindex + tilediff * (size_x - 1)], 2, 2, GetTunnelBridgeTransportType(tile + TileDiffXY(0, tilediff)));
+ /* Store "IsBridge-Start" in Bit4 (Nope, this is the End) */
+ /* BridgeType in m_signals */
+ m_signals[bindex + tilediff * (size_x - 1)] = GetBridgeType(tile + TileDiffXY(0, tilediff));
+ /* Store Railtype */
+ if (GetTunnelBridgeTransportType(tile + TileDiffXY(0, tilediff)) == TRANSPORT_RAIL)
+ m_railroad[bindex + (tilediff * (size_x - 1))] |= (GetRailType(tile + TileDiffXY(0, tilediff)) << 6);
+ }
+ break;
+ default:
+ break;
+ }
+ if (tunnelbridge_error) {
+ /* ResetBridge on Error */
+ m_railroad[bindex] = 0;
+ m_signals[bindex] = 0;
+ } else {
+ SB(m_tiletype[bindex], 0, 4, CP_TILE_TUNNELBRIDGE);
+ SB(m_tiletype[bindex], 4, 1, IsTunnelTile(tile));
+ }
+ }
+ else {
+ /* Other directions, do nothing, since we have copied everything already */
+ }
+ }
+ }
+ break;
+
+ default:
+ SB(m_tiletype[bindex], 0, 4, CP_TILE_CLEAR);
+ /* Storing nothing */
+ break;
+ }
+ bindex++;
+ success = true;
+
+ }
+
+ if (success) SndPlayTileFx(SND_1F_SPLAT, end);
+}
+
+/* Get the height of a tile */
+uint CopyPaste::GetHeight(uint baseh, uint index)
+{
+ return baseh + m_heightmap[index];
+}
+
+Slope CopyPaste::GetSlope(uint index)
+{
+ int a = m_heightmap[index];
+ int min = a;
+ int b = m_heightmap[index + 1];
+ if (min > b) min = b;
+ int c = m_heightmap[index + GetWidth()];
+ if (min > c) min = c;
+ int d = m_heightmap[index + GetWidth() + 1];
+ if (min > d) min = d;
+
+ uint r = SLOPE_FLAT;
+
+ if (a -= min != 0) r += (--a << 4) + SLOPE_N;
+ if (c -= min != 0) r += (--c << 4) + SLOPE_E;
+ if (d -= min != 0) r += (--d << 4) + SLOPE_S;
+ if (b -= min != 0) r += (--b << 4) + SLOPE_W;
+
+ return (Slope)r;
+}
+
+TrackBits CopyPaste::GetCPTrackBits(uint index)
+{
+ if (GetCPTileType(index) == CP_TILE_RAIL) {
+ if (GetCPMinorTileType(index) != RAIL_TILE_DEPOT) return (TrackBits)GB(m_railroad[index], 0, 6);
+ } else if (GetCPTileType(index) == CP_TILE_ROAD) {
+ if (GetCPMinorTileType(index) == ROAD_TILE_CROSSING) return GB(m_railroad[index], 0, 4) == ROAD_X ? TRACK_BIT_Y : TRACK_BIT_X;
+ }
+ return TRACK_BIT_NONE;
+}
+
+/** Get the major tiletype of a tile*/
+CopyPaste::CopyPasteTileType CopyPaste::GetCPTileType(uint index)
+{
+ return (CopyPasteTileType)GB(m_tiletype[index], 0, 4);
+}
+
+/** Get the minor tiletype of a tile*/
+uint CopyPaste::GetCPMinorTileType(uint index)
+{
+ return GB(m_tiletype[index], 4, 4);
+}
+/**
+ * Rotate an array.
+ * @param dir 1: rotate CW
+ * -1: rotate CCW
+ **/
+template
+static void rotate(T* b, int w, int h, int dir)
+{
+ int i, len, x, y, src, target;
+
+ /* Allocate a temporary array */
+ len = w * h;
+ T* tmp = MallocT(len);
+
+ /* Copy array to new allocated array: */
+ for (i = 0; i < len; i++)
+ tmp[i] = b[i];
+
+ /* Copy rotated values back to original array */
+ if (dir == 1) {
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ /*X index is now the old Y index
+ * Y index is w - x
+ */
+ src = (y * w) + x;
+ target = (((w - 1) - x) * h) + y;
+ b[target] = tmp[src];
+ }
+ }
+ }
+ else if (dir == -1) {
+ /* Copy rotated values back to original array */
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ /* X index is now the old Y index
+ * Y index is w - x
+ */
+ src = (y * w) + x;
+ target = (x * h) + (h - 1 - y);
+ b[target] = tmp[src];
+ }
+ }
+ }
+
+ /* Release temp array */
+ free(tmp);
+}
+
+/**
+ * Mirror array.
+ * @param axis 0: horizontal
+ * 1: vertical
+ **/
+template
+static void mirror(T* b, int w, int h, Axis axis)
+{
+ int x, y;
+
+
+ switch (axis) {
+ case AXIS_X:
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < (w / 2); x++) {
+ Swap(b[x + (y * w)], b[(w - x - 1) + (y * w)]);
+ }
+ }
+ break;
+ case AXIS_Y:
+ for (y = 0; y < (h / 2); y++) {
+ for (x = 0; x < w; x++) {
+ Swap(b[x + (y * w)], b[ x + ((h - y - 1) * w)]);
+ }
+ }
+ break;
+ default: NOT_REACHED();
+ }
+}
+
+/**
+ * Rotates the copied content ClockWise
+ * This is done by first rotating the array indices,
+ * then rotating the field contents
+ **/
+void CopyPaste::RotateSelectionCW()
+{
+ int w = GetWidth() - 1;
+ int h = GetHeight() - 1;
+ uint8 storelocation;
+ int index, len;
+
+ uint8 tmp8;
+ uint16 tmp16;
+
+ /* Rotate array indices */
+ rotate(m_heightmap, GetWidth(), GetHeight(), 1);
+ rotate(m_terrain_needed, GetWidth(), GetHeight(), 1);
+ rotate(m_tiletype, w, h, 1);
+ rotate(m_railroad, w, h, 1);
+ rotate(m_signals,w, h, 1);
+
+ /* Rotate array content (tracks, depots etc..) */
+ len = w * h;
+ for (index = 0; index < len; index++) {
+
+ switch (GetCPTileType(index)) {
+ case CP_TILE_RAIL:
+ if (GetCPMinorTileType(index) == RAIL_TILE_DEPOT) {
+ /* Depot */
+ SB(m_railroad[index], 0, 2, ChangeDiagDir((DiagDirection)GB(m_railroad[index], 0, 2), DIAGDIRDIFF_90RIGHT));
+ break;
+ }
+ /* Rotate Tracks */
+ /* Copy tracks to temp variable */
+ tmp8 = m_railroad[index];
+ /* Clear Tracks: bits 0-5 */
+ m_railroad[index] &= ~((1 << 6) - 1);
+ /* Copy back + rotate
+ * TODO exchange with arithmetic or lookup-table version...shorten...
+ */
+ if (tmp8 & TRACK_BIT_Y) m_railroad[index] |= TRACK_BIT_X;
+ if (tmp8 & TRACK_BIT_X) m_railroad[index] |= TRACK_BIT_Y;
+ if (tmp8 & TRACK_BIT_LEFT) m_railroad[index] |= TRACK_BIT_UPPER;
+ if (tmp8 & TRACK_BIT_RIGHT) m_railroad[index] |= TRACK_BIT_LOWER;
+ if (tmp8 & TRACK_BIT_LOWER) m_railroad[index] |= TRACK_BIT_LEFT;
+ if (tmp8 & TRACK_BIT_UPPER) m_railroad[index] |= TRACK_BIT_RIGHT;
+
+ if (GetCPMinorTileType(index) == RAIL_TILE_SIGNALS) {
+ /* Signals */
+ /* copy original signals to temporary variable */
+ tmp16 = m_signals[index];
+ /* Clear Signals: Bits 0-2 */
+ ClrBit(m_signals[index], 0);
+ ClrBit(m_signals[index], 1);
+ /* Copy back + rotate position */
+ storelocation = 6;
+ /* We already rotated the rail, so the TRACK_BIT_xxxx are the rotated ones */
+ if ((m_railroad[index] & TRACK_BIT_Y) && HasBit(tmp16, 0)) {
+ SetBit(m_signals[index], 0);
+ }
+ if ((m_railroad[index] & TRACK_BIT_X) && HasBit(tmp16, 0)) {
+ SetBit(m_signals[index], 0);
+ SB(m_signals[index], storelocation, 2, MirrorSignalDirection(GB(m_signals[index], storelocation, 2)));
+ }
+ if ((m_railroad[index] & TRACK_BIT_RIGHT) && HasBit(tmp16, 0)) {
+ SetBit(m_signals[index], 1);
+ SB(m_signals[index], storelocation, 2, MirrorSignalDirection(GB(m_signals[index], storelocation, 2)));
+ storelocation = 8;
+ }
+ if ((m_railroad[index] & TRACK_BIT_LEFT) && HasBit(tmp16, 1)) {
+ SetBit(m_signals[index], 0);
+ SB(m_signals[index], storelocation, 2, MirrorSignalDirection(GB(m_signals[index], storelocation, 2)));
+ if (storelocation == 8) {
+ /* Exchange Storelocations */
+ SwapSignalInfo(index);
+ }
+ storelocation = 8;
+ }
+ if (m_railroad[index] & TRACK_BIT_UPPER && HasBit(tmp16, 0)) {
+ SetBit(m_signals[index], 0);
+ }
+ if (m_railroad[index] & TRACK_BIT_LOWER && HasBit(tmp16, 1)) {
+ SetBit(m_signals[index], 1);
+ }
+
+ }
+ break;
+
+ case CP_TILE_ROAD:
+ if (GetCPMinorTileType(index) == ROAD_TILE_DEPOT) {
+ /* Depot */
+ SB(m_railroad[index], 0, 2, ChangeDiagDir((DiagDirection)GB(m_railroad[index], 0, 2), DIAGDIRDIFF_90RIGHT));
+ break;
+ }
+
+ /* rotate one-way roads */
+ if (m_railroad[index] & ROAD_Y && GetCPMinorTileType(index) == ROAD_TILE_NORMAL) {
+ SB(m_signals[index], 0, 2, MirrorOneWayRoadDirection((DisallowedRoadDirections)GB(m_signals[index], 0, 2)));
+ }
+ /* Road: */
+ SB(m_railroad[index], 0, 4, RotateRoadBits((RoadBits)GB(m_railroad[index], 0, 4), DIAGDIRDIFF_90RIGHT));
+ /* Trams: */
+ SB(m_railroad[index], 4, 4, RotateRoadBits((RoadBits)GB(m_railroad[index], 4, 4), DIAGDIRDIFF_90RIGHT));
+
+
+ break;
+
+ case CP_TILE_TUNNELBRIDGE:
+ /* tunnel/bridge */
+ SB(m_railroad[index], 0, 2, ChangeDiagDir((DiagDirection)GB(m_railroad[index], 0, 2), DIAGDIRDIFF_90RIGHT));
+
+ break;
+
+ default: break;
+ }
+
+ }
+
+ Swap(this->m_width, this->m_height);
+}
+
+/**
+ * Rotates the copied content CounterClockWise
+ * This is done by first rotating the array indices,
+ * then rotating the field contents
+ **/
+void CopyPaste::RotateSelectionCCW()
+{
+ int w = GetWidth() - 1;
+ int h = GetHeight() - 1;
+ uint8 storelocation;
+ int index, len;
+
+ uint8 tmp8;
+ uint16 tmp16;
+
+ /* Rotate array indices */
+ rotate(m_heightmap, GetWidth(), GetHeight(), -1);
+ rotate(m_terrain_needed, GetWidth(), GetHeight(), -1);
+ rotate(m_tiletype, w, h, -1);
+ rotate(m_railroad, w, h, -1);
+ rotate(m_signals,w, h, -1);
+
+ /* Rotate array content (tracks, depots etc..) */
+ len = w * h;
+ for (index = 0; index < len; index++) {
+ switch (GetCPTileType(index)) {
+ case CP_TILE_RAIL:
+ if (GetCPMinorTileType(index) == RAIL_TILE_DEPOT) {
+ //Depot
+ SB(m_railroad[index], 0, 2, ChangeDiagDir((DiagDirection)GB(m_railroad[index], 0, 2), DIAGDIRDIFF_90LEFT));
+ break;
+ }
+ tmp8 = m_railroad[index];
+ /* Clear Tracks: bits 0-5 */
+ m_railroad[index] &= ~63U;
+ /* Copy back + rotate */
+ if (tmp8 & TRACK_BIT_Y) m_railroad[index] |= TRACK_BIT_X;
+ if (tmp8 & TRACK_BIT_X) m_railroad[index] |= TRACK_BIT_Y;
+ if (tmp8 & TRACK_BIT_RIGHT) m_railroad[index] |= TRACK_BIT_UPPER;
+ if (tmp8 & TRACK_BIT_LEFT) m_railroad[index] |= TRACK_BIT_LOWER;
+ if (tmp8 & TRACK_BIT_UPPER) m_railroad[index] |= TRACK_BIT_LEFT;
+ if (tmp8 & TRACK_BIT_LOWER) m_railroad[index] |= TRACK_BIT_RIGHT;
+ if (GetCPMinorTileType(index) == RAIL_TILE_SIGNALS) {
+ //Signals
+ //Rotate position
+ tmp16 = m_signals[index];
+ /* Clear Signals: Bits 0-2 */
+ ClrBit(m_signals[index], 0);
+ ClrBit(m_signals[index], 1);
+ //Copy back + rotate position
+ storelocation = 6;
+ /* We already rotated the rail, so the TRACK_BIT_xxxx are the rotated ones */
+ if (m_railroad[index] & TRACK_BIT_Y && HasBit(tmp16, 0)) {
+ SetBit(m_signals[index], 0);
+ SB(m_signals[index], storelocation, 2, MirrorSignalDirection(GB(m_signals[index], storelocation, 2)));
+ }
+ if (m_railroad[index] & TRACK_BIT_X && HasBit(tmp16, 0)) {
+ SetBit(m_signals[index], 0);
+ }
+ if (m_railroad[index] & TRACK_BIT_LEFT && HasBit(tmp16, 0)) {
+ SetBit(m_signals[index], 0);
+ storelocation = 8;
+ }
+ if (m_railroad[index] & TRACK_BIT_RIGHT && HasBit(tmp16, 1)) {
+ SetBit(m_signals[index], 1);
+ storelocation = 8;
+ }
+ if (m_railroad[index] & TRACK_BIT_LOWER && HasBit(tmp16, 0)) {
+ SetBit(m_signals[index], 1);
+ SB(m_signals[index], storelocation, 2, MirrorSignalDirection(GB(m_signals[index], storelocation, 2)));
+ storelocation = 8;
+ }
+ if (m_railroad[index] & TRACK_BIT_UPPER && HasBit(tmp16, 1)) {
+ SetBit(m_signals[index], 0);
+ SB(m_signals[index], storelocation, 2, MirrorSignalDirection(GB(m_signals[index], storelocation, 2)));
+ if (storelocation == 8) {
+ /* Exchange Storelocations */
+ SwapSignalInfo(index);
+ }
+ storelocation = 8;
+ }
+ }
+ break;
+
+ case CP_TILE_ROAD:
+ if (GetCPMinorTileType(index) == ROAD_TILE_DEPOT) {
+ //Depot
+ SB(m_railroad[index], 0, 2, ChangeDiagDir((DiagDirection)GB(m_railroad[index], 0, 2), DIAGDIRDIFF_90LEFT));
+ break;
+ }
+ if (m_railroad[index] & ROAD_X && GetCPMinorTileType(index) == ROAD_TILE_NORMAL) {
+ SB(m_signals[index], 0, 2, MirrorOneWayRoadDirection((DisallowedRoadDirections)GB(m_signals[index], 0, 2)));
+ }
+ //Road & Tram:
+ SB(m_railroad[index], 0, 4, RotateRoadBits((RoadBits)GB(m_railroad[index], 0, 4), DIAGDIRDIFF_90LEFT));
+ SB(m_railroad[index], 4, 4, RotateRoadBits((RoadBits)GB(m_railroad[index], 4, 4), DIAGDIRDIFF_90LEFT));
+
+ break;
+
+ case CP_TILE_TUNNELBRIDGE:
+ SB(m_railroad[index], 0, 2, ChangeDiagDir((DiagDirection)GB(m_railroad[index], 0, 2), DIAGDIRDIFF_90LEFT));
+ break;
+ default: break;
+ }
+
+ }
+
+ Swap(this->m_height, this->m_width);
+}
+
+void CopyPaste::MirrorSelectionHorizontal()
+{
+ int w = GetWidth() - 1;
+ int h = GetHeight() - 1;
+ uint8 storelocation;
+ int index, len;
+
+ uint8 tmp8;
+ uint16 tmp16;
+
+ /* Mirror array indices */
+ mirror(m_heightmap, GetWidth(), GetHeight(), AXIS_X);
+ mirror(m_terrain_needed, GetWidth(), GetHeight(), AXIS_X);
+ mirror(m_tiletype, w, h, AXIS_X);
+ mirror(m_railroad, w, h, AXIS_X);
+ mirror(m_signals,w, h, AXIS_X);
+
+ /* Mirror array content (left <-> right) */
+ len = w * h;
+ for (index = 0; index < len; index++) {
+ switch (GetCPTileType(index)) {
+ case CP_TILE_RAIL:
+ if (GetCPMinorTileType(index) == RAIL_TILE_DEPOT) {
+ //Depot
+ tmp8 = GB(m_railroad[index], 0, 2); //Extract bit 0-1
+ if (tmp8 == DIAGDIR_NE || tmp8 == DIAGDIR_SW) tmp8 = ReverseDiagDir((DiagDirection)tmp8);
+ SB(m_railroad[index], 0, 2, tmp8); // set
+ break;
+ }
+ tmp8 = m_railroad[index];
+ /* Clear Tracks: Bits 0-5 */
+ m_railroad[index] &= ~63U;
+ /* Copy back + mirror */
+ if (tmp8 & TRACK_BIT_X) m_railroad[index] |= TRACK_BIT_X;
+ if (tmp8 & TRACK_BIT_Y) m_railroad[index] |= TRACK_BIT_Y;
+ if (tmp8 & TRACK_BIT_LEFT) m_railroad[index] |= TRACK_BIT_UPPER;
+ if (tmp8 & TRACK_BIT_RIGHT) m_railroad[index] |= TRACK_BIT_LOWER;
+ if (tmp8 & TRACK_BIT_UPPER) m_railroad[index] |= TRACK_BIT_LEFT;
+ if (tmp8 & TRACK_BIT_LOWER) m_railroad[index] |= TRACK_BIT_RIGHT;
+
+ if (GetCPMinorTileType(index) == RAIL_TILE_SIGNALS) {
+ //Signals
+ //Mirror position
+ tmp16 = m_signals[index];
+ //Copy back + mirror position
+ storelocation = 6;
+ if (m_railroad[index] & TRACK_BIT_X && HasBit(tmp16, 0)) {
+ SB(m_signals[index], storelocation, 2, MirrorSignalDirection(GB(m_signals[index], storelocation, 2)));
+ }
+ if (m_railroad[index] & TRACK_BIT_LEFT && HasBit(tmp16, 0)) {
+ SB(m_signals[index], storelocation, 2, MirrorSignalDirection(GB(m_signals[index], storelocation, 2)));
+ storelocation = 8;
+ }
+ if (m_railroad[index] & TRACK_BIT_RIGHT && HasBit(tmp16, 1)) {
+ SB(m_signals[index], storelocation, 2, MirrorSignalDirection(GB(m_signals[index], storelocation, 2)));
+ storelocation = 8;
+ }
+ if (m_railroad[index] & TRACK_BIT_UPPER && HasBit(tmp16, 0)) {
+ SB(m_signals[index], storelocation, 2, MirrorSignalDirection(GB(m_signals[index], storelocation, 2)));
+ storelocation = 8;
+ }
+ if (m_railroad[index] & TRACK_BIT_LOWER && HasBit(tmp16, 1)) {
+ SB(m_signals[index], storelocation, 2, MirrorSignalDirection(GB(m_signals[index], storelocation, 2)));
+ storelocation = 8;
+ }
+ }
+ break;
+
+ case CP_TILE_ROAD:
+ if (GetCPMinorTileType(index) == ROAD_TILE_DEPOT) {
+ //Depot
+ tmp8 = GB(m_railroad[index], 0, 2); //Extract bit 0-1
+ if (tmp8 == DIAGDIR_NE || tmp8 == DIAGDIR_SW) tmp8 = ReverseDiagDir((DiagDirection)tmp8);
+ SB(m_railroad[index], 0, 2, tmp8); // set
+ break;
+ }
+ //Road:
+ //swap horizontal roadpieces
+ tmp8 = m_railroad[index];
+ m_railroad[index] &= ~(ROAD_NE | ROAD_SW | ((ROAD_NE | ROAD_SW) << 4)); //Clear specific road bits
+ if ((tmp8 & ROAD_NE) > 0) m_railroad[index] |= ROAD_SW;
+ if ((tmp8 & ROAD_SW) > 0) m_railroad[index] |= ROAD_NE;
+ if ((tmp8 & (ROAD_NE << 4)) > 0) m_railroad[index] |= (ROAD_SW << 4);
+ if ((tmp8 & (ROAD_SW << 4)) > 0) m_railroad[index] |= (ROAD_NE << 4);
+
+ if ((tmp8 & ROAD_X) && GetCPMinorTileType(index) == ROAD_TILE_NORMAL) {
+ SB(m_signals[index], 0, 2, MirrorOneWayRoadDirection((DisallowedRoadDirections)GB(m_signals[index], 0, 2)));
+ }
+
+ break;
+
+ case CP_TILE_TUNNELBRIDGE:
+ /* Tunnel/Bridge
+ * just mirror direction
+ */
+ tmp8 = GB(m_railroad[index], 0, 2); //Extract bit 001
+ if (tmp8 == DIAGDIR_NE || tmp8 == DIAGDIR_SW) tmp8 = ReverseDiagDir((DiagDirection)tmp8);
+ SB(m_railroad[index], 0, 2, tmp8); // set
+
+ break;
+
+ default: break;
+ }
+
+ }
+}
+
+void CopyPaste::MirrorSelectionVertical()
+{
+ int w = GetWidth() - 1;
+ int h = GetHeight() - 1;
+ uint8 storelocation;
+ int index, len;
+
+ uint8 tmp8;
+ uint16 tmp16;
+
+ //Mirror arrays
+ mirror(m_heightmap, GetWidth(), GetHeight(), AXIS_Y);
+ mirror(m_terrain_needed, GetWidth(), GetHeight(), AXIS_Y);
+ mirror(m_tiletype, w, h, AXIS_Y);
+ mirror(m_railroad, w, h, AXIS_Y);
+ mirror(m_signals,w, h, AXIS_Y);
+
+ //Mirror array content (up <-> down)
+ len = w * h;
+ for (index = 0; index < len; index++) {
+ switch (GetCPTileType(index)) {
+ case CP_TILE_RAIL:
+ if (GetCPMinorTileType(index) == RAIL_TILE_DEPOT) {
+ //Depot
+ tmp8 = GB(m_railroad[index], 0, 2); //Extract bit 0-1
+ if (tmp8 == DIAGDIR_NW || tmp8 == DIAGDIR_SE) tmp8 = ReverseDiagDir((DiagDirection)tmp8);
+ SB(m_railroad[index], 0, 2, tmp8); // set
+ break;
+ }
+ tmp8 = m_railroad[index];
+ //Clear Tracks
+ m_railroad[index] &= ~63U; //Clear bits 0-5
+ //Copy back + mirror
+ if (tmp8 & TRACK_BIT_X) m_railroad[index] |= TRACK_BIT_X;
+ if (tmp8 & TRACK_BIT_Y) m_railroad[index] |= TRACK_BIT_Y;
+ if (tmp8 & TRACK_BIT_RIGHT) m_railroad[index] |= TRACK_BIT_UPPER;
+ if (tmp8 & TRACK_BIT_LEFT) m_railroad[index] |= TRACK_BIT_LOWER;
+ if (tmp8 & TRACK_BIT_LOWER) m_railroad[index] |= TRACK_BIT_LEFT;
+ if (tmp8 & TRACK_BIT_UPPER) m_railroad[index] |= TRACK_BIT_RIGHT;
+ if (GetCPMinorTileType(index) == RAIL_TILE_SIGNALS) {
+ //Signals
+ //Mirror position
+ tmp16 = m_signals[index];
+ //Clear Signals
+ ClrBit(m_signals[index], 0);
+ ClrBit(m_signals[index], 1);
+ //Copy back + mirror position
+ storelocation = 6;
+ if (m_railroad[index] & TRACK_BIT_X && HasBit(tmp16, 0)) {
+ SetBit(m_signals[index], 0);
+ }
+ if (m_railroad[index] & TRACK_BIT_Y && HasBit(tmp16, 0)) {
+ SetBit(m_signals[index], 0);
+ SB(m_signals[index], storelocation, 2, MirrorSignalDirection(GB(m_signals[index], storelocation, 2)));
+ }
+ if (m_railroad[index] & TRACK_BIT_RIGHT && HasBit(tmp16, 0)) {
+ SetBit(m_signals[index], 1);
+ storelocation = 8;
+ }
+ if (m_railroad[index] & TRACK_BIT_LEFT && HasBit(tmp16, 1)) {
+ SetBit(m_signals[index], 0);
+ if (storelocation == 8) {
+ /* Exchange Storelocations */
+ SwapSignalInfo(index);
+ }
+ storelocation = 8;
+ }
+ if (m_railroad[index] & TRACK_BIT_LOWER && HasBit(tmp16, 0)) {
+ SetBit(m_signals[index], 1);
+ storelocation = 8;
+ }
+ if (m_railroad[index] & TRACK_BIT_UPPER && HasBit(tmp16, 1)) {
+ SetBit(m_signals[index], 0);
+ if (storelocation == 8) {
+ /* Exchange Storelocations */
+ SwapSignalInfo(index);
+ }
+ storelocation = 8;
+ }
+
+ }
+ break;
+
+ case CP_TILE_ROAD:
+ if (GetCPMinorTileType(index) == ROAD_TILE_DEPOT) {
+ //Depot
+ tmp8 = GB(m_railroad[index], 0, 2); //Extract bit 0-1
+ if (tmp8 == DIAGDIR_NW || tmp8 == DIAGDIR_SE) tmp8 = ReverseDiagDir((DiagDirection)tmp8);
+ SB(m_railroad[index], 0, 2, tmp8); // set
+ break;
+ }
+ //Road:
+ //swap horizontal roadpieces
+ tmp8 = m_railroad[index];
+ m_railroad[index] &= ~(ROAD_NW | ROAD_SE | ((ROAD_NW | ROAD_SE) << 4)); //Clear specific road bits
+ if ((tmp8 & ROAD_NW) > 0) m_railroad[index] |= ROAD_SE;
+ if ((tmp8 & ROAD_SE) > 0) m_railroad[index] |= ROAD_NW;
+ if ((tmp8 & (ROAD_NW << 4)) > 0) m_railroad[index] |= (ROAD_SE << 4);
+ if ((tmp8 & (ROAD_SE << 4)) > 0) m_railroad[index] |= (ROAD_NW << 4);
+
+ if ((tmp8 & ROAD_Y) && GetCPMinorTileType(index) == ROAD_TILE_NORMAL) {
+ SB(m_signals[index], 0, 2, MirrorOneWayRoadDirection((DisallowedRoadDirections)GB(m_signals[index], 0, 2)));
+ }
+
+ break;
+
+ case CP_TILE_TUNNELBRIDGE:
+ /* Tunnel / Bridge */
+ tmp8 = GB(m_railroad[index], 0, 2); //Extract bit 1-2
+ if (tmp8 == DIAGDIR_NW || tmp8 == DIAGDIR_SE) tmp8 = ReverseDiagDir((DiagDirection)tmp8);
+ SB(m_railroad[index], 0, 2, tmp8); // set
+ break;
+ default: break;
+ }
+
+ }
+}
+
+
diff --git a/src/copy_paste.h b/src/copy_paste.h
new file mode 100644
--- /dev/null
+++ b/src/copy_paste.h
@@ -0,0 +1,113 @@
+/* $Id: command_queue.h 4998 2006-05-30 16:13:41Z Frostregen $ */
+
+#ifndef COPY_PASTE_H
+#define COPY_PASTE_H
+
+#include "map_type.h"
+#include "command_type.h"
+#include "signal_type.h"
+#include "track_type.h"
+#include "slope_type.h"
+#include "road_map.h"
+#include "saveload/saveload.h"
+
+class CopyPaste {
+public:
+ bool m_copy_with_rail; ///< If rail should be copied
+ bool m_copy_with_road; ///< If road should be copied
+ bool m_copy_with_other; ///< If stuff owned by other players should be copied
+
+ uint8 m_paste_vacant_terrain; ///< If empty terrain should be recreated. 0 = no terraform, 1 = terraform only needed, 2 = terraform all terrain
+ bool m_convert_rail; ///< If rails should be converted to currently selected railtype
+ bool m_clear_before_build; ///< If terrain should be bulldozed before we try to paste it
+ bool m_toggle_signal_direction; ///< If signal direction should be toggled when pasting
+
+private:
+ uint32 m_width;
+ uint32 m_height;
+ StringID error_str;
+ char *error_msg;
+
+ CommandCost m_costs; ///< Stores the costs needed for template paste - estimate
+
+ /** Storage space for copied area
+ * TODO: Convert to struct (saveload...)
+ */
+ int8 *m_heightmap; ///< | Move terrain needed into this...
+ uint8 *m_terrain_needed; ///< 2Bit needed
+ uint8 *m_tiletype; ///< 8Bit needed
+ uint8 *m_railroad; ///< 8Bit needed
+ uint16 *m_signals; ///< 15Bit needed
+ //TODO: uint8 *m_station;
+
+public:
+ enum CopyPasteTileType {
+ CP_TILE_CLEAR,
+ CP_TILE_RAIL,
+ CP_TILE_ROAD,
+ CP_TILE_TUNNELBRIDGE,
+ CP_TILE_STATION,
+ };
+ explicit CopyPaste();
+ ~CopyPaste();
+
+ SaveOrLoadResult SaveLoadTemplate(const char *filename, int mode);
+ const char *GetErrorString();
+ bool IsSomethingCopied(); ///< Returns if something is in our copy buffer.
+ void AllocateMapArray(uint32 max_tiles); ///< allocate a map array
+ void ClearCopyArrays(); ///< Clears content of copy buffers for current width/height, but does NOT reset width/height.
+
+ void CopyArea(TileIndex end, TileIndex start); ///< Copies given area into copy buffer
+ void PasteArea(TileIndex tile); ///< Paste copied content onto map, taking care of multiplayer/singleplayer environment.
+
+ void RotateSelectionCCW();
+ void RotateSelectionCW();
+ void MirrorSelectionHorizontal();
+ void MirrorSelectionVertical();
+ uint GetHeight(uint baseh, uint index);
+ Slope GetSlope(uint index);
+ CopyPasteTileType GetCPTileType(uint index);
+ uint GetCPMinorTileType(uint index);
+ TrackBits GetCPTrackBits(uint index);
+
+ FORCEINLINE uint32 GetWidth() { return m_width; }; ///< Used by the GUI
+ FORCEINLINE uint32 GetHeight() { return m_height; };
+
+private:
+ void SetError(StringID message, StringID extra = INVALID_STRING_ID);
+
+ void internal_PasteArea(TileIndex tile); ///< internal PasteArea method
+
+ void CP_DoCommand(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd); ///< Special DoCommand for CopyPaste
+
+ void CP_RaiseLowerLand (TileIndex tile, int mode);
+ void CP_PlaceRail (TileIndex tile, int cmd, uint32 railtype);
+ void CP_PlaceSignals (TileIndex tile, Track track, SignalType type, uint direction, bool semaphore);
+ void CP_PlaceRoad (TileIndex tile, uint8 road_bits);
+ void CP_PlaceRoadStop(TileIndex tile, uint8 direction, uint8 roadtype, bool truck_stop, bool drive_through);
+ void CP_PlaceRail_Tunnel(TileIndex tile, uint32 railtype);
+ void CP_PlaceRoad_Tunnel(TileIndex tile, uint8 roadtype);
+ void CP_Build_Bridge (TileIndex start, TileIndex end, uint8 bridgetype, uint8 transport_type, uint8 rail_road_type);
+ void CP_PlaceRail_Depot (TileIndex tile, uint8 railtype, uint8 direction);
+ void CP_PlaceRoad_Depot (TileIndex tile, uint8 direction_type);
+ void CP_PlaceWaypoint (TileIndex tile, uint8 waypoint_type);
+ void CP_ClearTile (TileIndex start_tile, TileIndex end_tile);
+
+ uint8 MirrorSignalDirection(uint8 direction);
+ DisallowedRoadDirections MirrorOneWayRoadDirection(DisallowedRoadDirections drd);
+ void SwapSignalInfo(uint index);
+ void PasteSignals(uint index, TileIndex tile);
+ void PasteLandscape(TileIndex tile);
+
+ void TerrainNeededAroundTile(TileIndex tindex, TileIndex bindex);
+ int8 ClampToRight(TileIndex index, int8 baseh, int8 h_tile);
+ int8 ClampToUp(TileIndex index, int8 baseh, int8 h_tile, int32 size_x);
+
+ FORCEINLINE void SetWidth(uint32 width) { m_width = width; };
+ FORCEINLINE void SetHeight(uint32 height) { m_height = height; };
+};
+
+extern CopyPaste _copy_paste;
+
+#endif /* COPY_PASTE_H */
+
diff --git a/src/copy_paste_gui.cpp b/src/copy_paste_gui.cpp
new file mode 100644
--- /dev/null
+++ b/src/copy_paste_gui.cpp
@@ -0,0 +1,314 @@
+/* $Id: copy_paste_gui.cpp 4998 2006-05-28 07:45:14Z Frostregen $ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "gui.h"
+#include "window_gui.h"
+#include "viewport_type.h"
+#include "viewport_func.h"
+#include "gfx_func.h"
+#include "strings_type.h"
+#include "clear_func.h"
+#include "window_type.h"
+#include "window_func.h"
+#include "sound_type.h"
+#include "sound_func.h"
+#include "tilehighlight_type.h"
+#include "tilehighlight_func.h"
+#include "company_func.h"
+#include "tile_type.h"
+#include "rail_type.h"
+#include "rail_gui.h"
+#include "sprite.h"
+#include "fios.h"
+#include "copy_paste.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+
+
+/** Current railtype. Used for autoconversion */
+static RailType _last_railtype = RAILTYPE_RAIL;
+
+/* **** GUI Code for Copy&Paste **** */
+
+/** Enum referring to the widgets of the copy paste window */
+enum CopyPasteWidgets {
+ CPW_CLOSEBOX = 0,
+ CPW_CAPTION,
+ CPW_STICKYBOX,
+ CPW_SPACER_1,
+ CPW_SPACER_2,
+ CPW_SPACER_3,
+ CPW_COPY,
+ CPW_PASTE,
+ CPW_LOAD,
+ CPW_SAVE,
+ CPW_ROTATE_LEFT,
+ CPW_ROTATE_RIGHT,
+ CPW_MIRROR_HORIZONTAL,
+ CPW_MIRROR_VERTICAL,
+ CPW_TERRAIN,
+ CPW_DYNAMITE,
+ CPW_RAIL,
+ CPW_ROAD,
+ CPW_REVERSE_SIGNALS,
+ CPW_CONVERT_RAILTYPE,
+ CPW_ONLY_OWN,
+
+ CPW_FIRST_CLICKABLE = CPW_COPY,
+ CPW_LAST_CLICKABLE = CPW_ONLY_OWN,
+};
+
+struct CopyPasteWindow : Window {
+int last_user_action; ///< Last started user action.
+public:
+ CopyPasteWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
+ {
+ this->InitNested(desc, window_number);
+ this->last_user_action = WIDGET_LIST_END;
+
+ /* Set the button states according to variable content */
+ if (_copy_paste.m_clear_before_build) this->LowerWidget(CPW_DYNAMITE);
+ if (_copy_paste.m_toggle_signal_direction) this->LowerWidget(CPW_REVERSE_SIGNALS);
+ if (_copy_paste.m_convert_rail) this->LowerWidget(CPW_CONVERT_RAILTYPE);
+ if (_copy_paste.m_copy_with_rail) this->LowerWidget(CPW_RAIL);
+ if (_copy_paste.m_copy_with_road) this->LowerWidget(CPW_ROAD);
+ if (_copy_paste.m_copy_with_other)this->LowerWidget(CPW_ONLY_OWN);
+ }
+
+ virtual void OnPaint()
+ {
+ SetWidgetsDisabledState(!_copy_paste.IsSomethingCopied(), CPW_PASTE, CPW_SAVE,
+ CPW_ROTATE_LEFT, CPW_ROTATE_RIGHT, CPW_MIRROR_HORIZONTAL, CPW_MIRROR_VERTICAL,
+ WIDGET_LIST_END);
+ /* Set image for tri-state button */
+ this->GetWidget(CPW_TERRAIN)->widget_data = SPR_IMG_MINUS_TERRAIN + _copy_paste.m_paste_vacant_terrain;
+
+ this->DrawWidgets();
+
+ /* Draw CylinderGuy in CompanyColor, if unclicked */
+ if (!this->IsWidgetLowered(CPW_ONLY_OWN))
+ DrawSprite(SPR_IMG_ONLY_OWN, COMPANY_SPRITE_COLOUR(_current_company), this->GetWidget(CPW_ONLY_OWN)->pos_x + 1, this->GetWidget(CPW_ONLY_OWN)->pos_y + 1);
+ }
+
+ virtual void OnClick(Point pt, int widget, int click_count)
+ {
+ SetWidgetsDisabledState(!_copy_paste.IsSomethingCopied(), CPW_PASTE, CPW_SAVE,
+ CPW_ROTATE_LEFT, CPW_ROTATE_RIGHT, CPW_MIRROR_HORIZONTAL, CPW_MIRROR_VERTICAL,
+ WIDGET_LIST_END);
+ if (this->IsWidgetDisabled(widget)) return;
+ if ((widget >= CPW_FIRST_CLICKABLE) && (widget <= CPW_LAST_CLICKABLE)) {
+ if (widget != CPW_COPY && widget != CPW_PASTE &&
+ widget != CPW_DYNAMITE && widget != CPW_REVERSE_SIGNALS &&
+ widget != CPW_RAIL && widget != CPW_CONVERT_RAILTYPE &&
+ widget != CPW_ROAD && widget != CPW_ONLY_OWN) {
+ this->HandleButtonClick(widget);
+ }
+ SndPlayFx(SND_15_BEEP);
+ switch (widget) {
+ case CPW_COPY:
+ HandlePlacePushButton(this, CPW_COPY, SPR_CURSOR_COPY, HT_RECT);
+ this->last_user_action = widget;
+ break;
+
+ case CPW_PASTE:
+ HandlePlacePushButton(this, CPW_PASTE, SPR_CURSOR_PASTE, HT_PREVIEW);
+ this->last_user_action = widget;
+ break;
+
+ case CPW_LOAD:
+ _copy_paste.m_toggle_signal_direction = false;
+ /* fallthrough */
+
+ case CPW_SAVE:
+ ShowSaveLoadDialog(widget == CPW_SAVE ? SLD_SAVE_TEMPLATE : SLD_LOAD_TEMPLATE);
+ break;
+
+ case CPW_ROTATE_LEFT:
+ case CPW_ROTATE_RIGHT:
+ if (widget == CPW_ROTATE_LEFT) _copy_paste.RotateSelectionCCW();
+ if (widget == CPW_ROTATE_RIGHT) _copy_paste.RotateSelectionCW();
+ break;
+
+ case CPW_MIRROR_HORIZONTAL:
+ case CPW_MIRROR_VERTICAL:
+ if (widget == CPW_MIRROR_HORIZONTAL) _copy_paste.MirrorSelectionHorizontal();
+ if (widget == CPW_MIRROR_VERTICAL) _copy_paste.MirrorSelectionVertical();
+
+ /* Toggle SignalDir */
+ this->OnClick(Point(), CPW_REVERSE_SIGNALS, 1);
+ break;
+
+ case CPW_TERRAIN:
+ _copy_paste.m_paste_vacant_terrain++;
+ if (_copy_paste.m_paste_vacant_terrain > 2) _copy_paste.m_paste_vacant_terrain = 0;
+ break;
+
+ case CPW_DYNAMITE: case CPW_REVERSE_SIGNALS:
+ case CPW_RAIL: case CPW_CONVERT_RAILTYPE:
+ case CPW_ROAD: case CPW_ONLY_OWN: {
+ this->SetDirty();
+ this->ToggleWidgetLoweredState(widget);
+ bool state = IsWidgetLowered(widget);
+ switch (widget) {
+ case CPW_DYNAMITE: _copy_paste.m_clear_before_build = state; break;
+ case CPW_RAIL: _copy_paste.m_copy_with_rail = state; break;
+ case CPW_ROAD: _copy_paste.m_copy_with_road = state; break;
+ case CPW_REVERSE_SIGNALS: _copy_paste.m_toggle_signal_direction = state; break;
+ case CPW_CONVERT_RAILTYPE: _copy_paste.m_convert_rail = state; break;
+ case CPW_ONLY_OWN: _copy_paste.m_copy_with_other = state; break;
+ default: NOT_REACHED();
+ }
+ } break;
+ default: break;
+ }
+
+ /* Set Selection size to Copy size */
+ if (this->IsWidgetLowered(CPW_PASTE)) {
+ if (_copy_paste.GetWidth() > 0)
+ SetTileSelectSize(_copy_paste.GetWidth() - 1, _copy_paste.GetHeight() - 1);
+ } else {
+ SetTileSelectSize(1, 1);
+ }
+ }
+ }
+
+ virtual void OnPlaceObject(Point pt, TileIndex tile)
+ {
+ switch (this->last_user_action) {
+ case CPW_COPY:
+ VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_COPY_AREA);
+ VpSetPlaceSizingLimit(255);
+ break;
+
+ case CPW_PASTE:
+ _copy_paste.PasteArea(tile);
+ break;
+ }
+ }
+
+ virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+ {
+ VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+ }
+
+ virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+ {
+ if (pt.x != -1) {
+ switch (select_proc) {
+ case DDSP_COPY_AREA:
+ _copy_paste.CopyArea(end_tile, start_tile);
+ /* Reset SignalDir */
+ if (_copy_paste.m_toggle_signal_direction) this->OnClick(Point(), CPW_REVERSE_SIGNALS, 1);
+ this->SetDirty();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ virtual void OnPlaceObjectAbort()
+ {
+ /* UnclickWindowButtons "copy" and "paste" */
+ this->RaiseWidget(CPW_COPY);
+ this->RaiseWidget(CPW_PASTE);
+
+ this->SetDirty();
+ }
+
+ virtual void OnTimeout()
+ {
+ this->RaiseWidget(CPW_LOAD);
+ this->RaiseWidget(CPW_SAVE);
+ this->RaiseWidget(CPW_ROTATE_LEFT);
+ this->RaiseWidget(CPW_ROTATE_RIGHT);
+ this->RaiseWidget(CPW_MIRROR_HORIZONTAL);
+ this->RaiseWidget(CPW_MIRROR_VERTICAL);
+ this->RaiseWidget(CPW_TERRAIN);
+ this->SetDirty();
+ }
+
+ virtual void OnTick()
+ {
+ /* If railtype has changed, we need to update our GUI */
+ if (_last_railtype != _cur_railtype) {
+ const RailtypeInfo *rti = GetRailTypeInfo(_cur_railtype);
+ _last_railtype = _cur_railtype;
+ this->GetWidget(CPW_CONVERT_RAILTYPE)->widget_data = rti->gui_sprites.convert_rail;
+ this->SetDirty();
+ }
+ }
+};
+
+static const NWidgetPart _nested_copy_paste_widgets[] = {
+ NWidget(NWID_HORIZONTAL),
+ NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
+ NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_COPY_PASTE_TOOLBAR, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+ NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
+ EndContainer(),
+ NWidget(NWID_HORIZONTAL),
+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_COPY), SetMinimalSize(22,22),
+ SetFill(0, 1), SetDataTip(SPR_IMG_COPY, STR_COPY_PASTE_COPY_TOOLTIP),
+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_PASTE), SetMinimalSize(22,22),
+ SetFill(0, 1), SetDataTip(SPR_IMG_PASTE, STR_COPY_PASTE_PASTE_TOOLTIP),
+
+ NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), EndContainer(),
+
+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_LOAD), SetMinimalSize(22,22),
+ SetFill(0, 1), SetDataTip(SPR_IMG_LOAD, STR_COPY_PASTE_LOAD_TOOLTIP),
+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_SAVE), SetMinimalSize(22,22),
+ SetFill(0, 1), SetDataTip(SPR_IMG_SAVE, STR_COPY_PASTE_SAVE_TOOLTIP),
+
+ NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), EndContainer(),
+
+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_ROTATE_LEFT), SetMinimalSize(22,22),
+ SetFill(0, 1), SetDataTip(SPR_IMG_ROTATE_LEFT, STR_COPY_PASTE_ROTATE_LEFT_TOOLTIP),
+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_ROTATE_RIGHT), SetMinimalSize(22,22),
+ SetFill(0, 1), SetDataTip(SPR_IMG_ROTATE_RIGHT, STR_COPY_PASTE_ROTATE_RIGHT_TOOLTIP),
+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_MIRROR_HORIZONTAL), SetMinimalSize(22,22),
+ SetFill(0, 1), SetDataTip(SPR_IMG_MIRROR_HORIZONTAL, STR_COPY_PASTE_MIRROR_HORIZONTAL_TOOLTIP),
+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_MIRROR_VERTICAL), SetMinimalSize(22,22),
+ SetFill(0, 1), SetDataTip(SPR_IMG_MIRROR_VERTICAL, STR_COPY_PASTE_MIRROR_VERTICAL_TOOLTIP),
+
+ NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), EndContainer(),
+
+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_TERRAIN), SetMinimalSize(22,22),
+ SetFill(0, 1), SetDataTip(SPR_IMG_MINUS_TERRAIN, STR_COPY_PASTE_VACANT_TERRAIN_TOOLTIP),
+ NWidget(WWT_IMGBTN_2, COLOUR_DARK_GREEN, CPW_DYNAMITE), SetMinimalSize(22,22),
+ SetFill(0, 1), SetDataTip(SPR_IMG_MINUS_DYNAMITE, STR_COPY_PASTE_BULLDOZE_BEFORE_BUILD_TOOLTIP),
+ NWidget(WWT_IMGBTN_2, COLOUR_DARK_GREEN, CPW_RAIL), SetMinimalSize(22,22),
+ SetFill(0, 1), SetDataTip(SPR_IMG_NO_RAIL, STR_COPY_PASTE_WITHOUT_RAIL_TOOLTIP),
+ NWidget(WWT_IMGBTN_2, COLOUR_DARK_GREEN, CPW_ROAD), SetMinimalSize(22,22),
+ SetFill(0, 1), SetDataTip(SPR_IMG_NO_ROAD, STR_COPY_PASTE_WITHOUT_ROAD_TOOLTIP),
+ NWidget(WWT_IMGBTN_2, COLOUR_DARK_GREEN, CPW_REVERSE_SIGNALS), SetMinimalSize(22,22),
+ SetFill(0, 1), SetDataTip(SPR_IMG_MINUS_SIGNAL, STR_COPY_PASTE_TOGGLE_SIGNAL_DIRECTION_TOOLTIP),
+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_CONVERT_RAILTYPE), SetMinimalSize(22,22),
+ SetFill(0, 1), SetDataTip(SPR_IMG_CONVERT_RAIL, STR_COPY_PASTE_CONVERT_RAIL_TOOLTIP),
+ NWidget(WWT_IMGBTN_2, COLOUR_DARK_GREEN, CPW_ONLY_OWN), SetMinimalSize(22,22),
+ SetFill(0, 1), SetDataTip(SPR_IMG_ONLY_OWN, STR_COPY_PASTE_ONLY_OWN_TOOLTIP),
+ EndContainer(),
+};
+
+static const WindowDesc _copy_paste_desc(
+ WDP_ALIGN_TOOLBAR, 0, 0,
+ WC_COPY_PASTE, WC_SCEN_LAND_GEN,
+ WDF_CONSTRUCTION,
+ _nested_copy_paste_widgets, lengthof(_nested_copy_paste_widgets)
+);
+
+void ShowCopyPasteToolbarGui() // When clicking the button in the terrain generation gui
+{
+ AllocateWindowDescFront(&_copy_paste_desc, 0);
+}
+
+void ShowCopyPasteToolbar(int button) // When using a shortcut
+{
+ Window *w;
+ /* don't recreate the window if we're clicking on a button and the window exists. */
+ if (button < CPW_FIRST_CLICKABLE || !(w = FindWindowById(WC_COPY_PASTE, 0))) {
+ DeleteWindowByClass(WC_COPY_PASTE);
+ w = new CopyPasteWindow(&_copy_paste_desc, 0);
+ }
+ if (w != NULL) w->OnClick(Point(), button, 1);
+}
diff --git a/src/core/endian_type.hpp b/src/core/endian_type.hpp
--- a/src/core/endian_type.hpp
+++ b/src/core/endian_type.hpp
@@ -30,7 +30,7 @@
#define TTD_ENDIAN TTD_LITTLE_ENDIAN
#elif !defined(TESTING)
/* Else include endian[target/host].h, which has the endian-type, autodetected by the Makefile */
- #if defined(STRGEN) || defined(SETTINGSGEN)
+ #if defined(STRGEN)
#include "endian_host.h"
#else
#include "endian_target.h"
diff --git a/src/core/math_func.cpp b/src/core/math_func.cpp
--- a/src/core/math_func.cpp
+++ b/src/core/math_func.cpp
@@ -46,3 +46,54 @@ int GreatestCommonDivisor(int a, int b)
return a;
}
+
+/**
+ * Compute the integer square root.
+ * @param num Radicand.
+ * @return Rounded integer square root.
+ * @note Algorithm taken from http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
+ */
+uint32 IntSqrt(uint32 num)
+{
+ uint32 res = 0;
+ uint32 bit = 1UL << 30; // Second to top bit number.
+
+ /* 'bit' starts at the highest power of four <= the argument. */
+ while (bit > num) bit >>= 2;
+
+ while (bit != 0) {
+ if (num >= res + bit) {
+ num -= res + bit;
+ res = (res >> 1) + bit;
+ } else {
+ res >>= 1;
+ }
+ bit >>= 2;
+ }
+
+ /* Arithmetic rounding to nearest integer. */
+ if (num > res) res++;
+
+ return res;
+}
+
+/**
+ * Deterministic approximate division.
+ * Cancels out division errors stemming from the integer nature of the division over multiple runs.
+ * @param a Dividend.
+ * @param b Divisor.
+ * @return a/b or (a/b)+1.
+ */
+int DivideApprox(int a, int b)
+{
+ int random_like = ((a + b) * (a - b)) % b;
+
+ int remainder = a % b;
+
+ int ret = a / b;
+ if (abs(random_like) < abs(remainder)) {
+ ret += ((a < 0) ^ (b < 0)) ? -1 : 1;
+ }
+
+ return ret;
+}
diff --git a/src/core/math_func.hpp b/src/core/math_func.hpp
--- a/src/core/math_func.hpp
+++ b/src/core/math_func.hpp
@@ -317,6 +317,7 @@ static FORCEINLINE uint ToPercent16(uint
int LeastCommonMultiple(int a, int b);
int GreatestCommonDivisor(int a, int b);
+int DivideApprox(int a, int b);
/**
* Computes ceil(a / b) for non-negative a and b.
@@ -346,4 +347,6 @@ static FORCEINLINE int RoundDivSU(int a,
}
}
+uint32 IntSqrt(uint32 num);
+
#endif /* MATH_FUNC_HPP */
diff --git a/src/core/multimap.hpp b/src/core/multimap.hpp
new file mode 100644
--- /dev/null
+++ b/src/core/multimap.hpp
@@ -0,0 +1,249 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
+ */
+
+/** @file multimap.hpp Multimap with deterministic ordering of items with equal keys. */
+
+#ifndef MULTIMAP_HPP_
+#define MULTIMAP_HPP_
+
+#include
+#include